You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2023/05/31 12:54:54 UTC

[plc4x] branch develop updated (4389991a8b -> b330c7ce33)

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


    from 4389991a8b chore(plc4go): code sync
     new 09147a8d95 refactor(plc4go/spi): move transaction manager to own package
     new c4bf3ebd62 refactor(plc4go/spi): move WorkerPool to own package
     new b330c7ce33 feat(plc4go/spi): Introduce new WithCustomLogger option

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 plc4go/internal/bacnetip/Connection.go             |   5 +-
 plc4go/internal/bacnetip/Driver.go                 |   6 +-
 plc4go/internal/bacnetip/Reader.go                 |   7 +-
 plc4go/internal/cbus/Browser.go                    |  73 +-
 plc4go/internal/cbus/Browser_test.go               | 351 +++++-----
 plc4go/internal/cbus/CBusMessageMapper.go          |   8 +-
 plc4go/internal/cbus/CBusMessageMapper_test.go     | 589 +++++++++++-----
 plc4go/internal/cbus/Configuration.go              |  10 +-
 plc4go/internal/cbus/Configuration_test.go         |   5 +-
 plc4go/internal/cbus/Connection.go                 | 101 +--
 plc4go/internal/cbus/Connection_test.go            | 742 +++++++++++++--------
 plc4go/internal/cbus/Discoverer.go                 |  43 +-
 plc4go/internal/cbus/Discoverer_test.go            |  53 +-
 plc4go/internal/cbus/Driver.go                     |  39 +-
 plc4go/internal/cbus/Driver_test.go                |   8 +-
 plc4go/internal/cbus/MessageCodec.go               |  66 +-
 plc4go/internal/cbus/Reader.go                     |  40 +-
 plc4go/internal/cbus/Reader_test.go                |  35 +-
 plc4go/internal/cbus/Subscriber.go                 |  35 +-
 plc4go/internal/cbus/Writer.go                     |  22 +-
 plc4go/internal/cbus/Writer_test.go                |   6 +-
 .../internal/cbus/mock_RequestTransaction_test.go  |  12 +-
 plc4go/internal/cbus/mock_requirements.go          |   6 +-
 .../cbus/noGlobalLog_test.go}                      |   7 +-
 plc4go/internal/eip/Connection.go                  |   5 +-
 plc4go/internal/eip/EipDriver.go                   |   6 +-
 plc4go/internal/eip/Reader.go                      |   7 +-
 plc4go/internal/eip/Writer.go                      |   9 +-
 plc4go/internal/knxnetip/Discoverer.go             |  14 +-
 plc4go/internal/s7/Connection.go                   |   5 +-
 plc4go/internal/s7/Driver.go                       |   6 +-
 plc4go/internal/s7/Reader.go                       |   7 +-
 plc4go/internal/s7/Writer.go                       |   7 +-
 plc4go/pkg/api/driver.go                           |   2 +-
 plc4go/pkg/api/mock_PlcDriver_test.go              |  16 +-
 plc4go/pkg/api/mock_Transport_test.go              |  51 +-
 .../protocols/cbus/readwrite/model/StaticHelper.go |   7 +-
 plc4go/spi/default/DefaultCodec.go                 |  55 +-
 plc4go/spi/default/DefaultConnection.go            |  31 +-
 plc4go/spi/default/DefaultDriver.go                |   2 +-
 .../default/mock_DefaultDriverRequirements_test.go |  16 +-
 plc4go/spi/default/mock_DefaultDriver_test.go      |  16 +-
 plc4go/spi/mock_requirements.go                    |   4 +-
 plc4go/spi/options/Option.go                       |  35 +
 plc4go/spi/{utils => pool}/WorkerPool.go           |  82 ++-
 plc4go/spi/{utils => pool}/WorkerPool_test.go      |  55 +-
 .../spi/{ => pool}/mock_CompletionFuture_test.go   |   2 +-
 plc4go/spi/{utils => pool}/mock_Executor_test.go   |  43 +-
 plc4go/spi/{utils => pool}/mock_Runnable_test.go   |   2 +-
 plc4go/spi/testutils/TestUtils.go                  |  34 +
 .../RequestTransactionManager.go                   |  97 ++-
 .../RequestTransactionManager_test.go              |  49 +-
 .../mock_CompletionFuture_test.go                  |   2 +-
 .../mock_RequestTransactionManagerOption_test.go   |   2 +-
 .../mock_RequestTransactionManager_test.go         |  91 ++-
 .../mock_RequestTransactionRunnable_test.go        |  16 +-
 .../mock_RequestTransaction_test.go                |   2 +-
 plc4go/spi/{ => transactions}/mock_requirements.go |   6 +-
 plc4go/spi/transports/Transport.go                 |   7 +-
 plc4go/spi/transports/mock_Transport_test.go       |  50 +-
 plc4go/spi/transports/pcap/Transport.go            |  36 +-
 plc4go/spi/transports/serial/Transport.go          |  35 +-
 plc4go/spi/transports/tcp/Transport.go             |  14 +-
 plc4go/spi/transports/test/Transport.go            |  48 +-
 plc4go/spi/transports/udp/Transport.go             |  23 +-
 plc4go/spi/utils/mock_ExecutorOption_test.go       |  85 ---
 66 files changed, 2079 insertions(+), 1272 deletions(-)
 copy plc4go/{pkg/api/model/plc_request.go => internal/cbus/noGlobalLog_test.go} (88%)
 rename plc4go/spi/{utils => pool}/WorkerPool.go (80%)
 rename plc4go/spi/{utils => pool}/WorkerPool_test.go (93%)
 copy plc4go/spi/{ => pool}/mock_CompletionFuture_test.go (99%)
 rename plc4go/spi/{utils => pool}/mock_Executor_test.go (85%)
 copy plc4go/spi/{utils => pool}/mock_Runnable_test.go (99%)
 rename plc4go/spi/{ => transactions}/RequestTransactionManager.go (77%)
 rename plc4go/spi/{ => transactions}/RequestTransactionManager_test.go (94%)
 copy plc4go/spi/{ => transactions}/mock_CompletionFuture_test.go (99%)
 rename plc4go/spi/{ => transactions}/mock_RequestTransactionManagerOption_test.go (99%)
 rename plc4go/spi/{ => transactions}/mock_RequestTransactionManager_test.go (64%)
 rename plc4go/spi/{ => transactions}/mock_RequestTransactionRunnable_test.go (85%)
 rename plc4go/spi/{ => transactions}/mock_RequestTransaction_test.go (99%)
 copy plc4go/spi/{ => transactions}/mock_requirements.go (91%)
 delete mode 100644 plc4go/spi/utils/mock_ExecutorOption_test.go


[plc4x] 03/03: feat(plc4go/spi): Introduce new WithCustomLogger option

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit b330c7ce33647b379089d23a91d5788bc7b98a27
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 31 14:54:46 2023 +0200

    feat(plc4go/spi): Introduce new WithCustomLogger option
    
    With this option it is possible to supply a custom logger which will get used downstream.
    
    Benefit is that in production and test you can better assign logs and later downstream enrich them properly
---
 plc4go/internal/bacnetip/Connection.go             |   5 +-
 plc4go/internal/bacnetip/Driver.go                 |   6 +-
 plc4go/internal/bacnetip/Reader.go                 |   7 +-
 plc4go/internal/cbus/Browser.go                    |  73 +-
 plc4go/internal/cbus/Browser_test.go               | 351 +++++-----
 plc4go/internal/cbus/CBusMessageMapper.go          |   8 +-
 plc4go/internal/cbus/CBusMessageMapper_test.go     | 589 +++++++++++-----
 plc4go/internal/cbus/Configuration.go              |  10 +-
 plc4go/internal/cbus/Configuration_test.go         |   5 +-
 plc4go/internal/cbus/Connection.go                 | 101 +--
 plc4go/internal/cbus/Connection_test.go            | 742 +++++++++++++--------
 plc4go/internal/cbus/Discoverer.go                 |  43 +-
 plc4go/internal/cbus/Discoverer_test.go            |  53 +-
 plc4go/internal/cbus/Driver.go                     |  39 +-
 plc4go/internal/cbus/Driver_test.go                |   8 +-
 plc4go/internal/cbus/MessageCodec.go               |  66 +-
 plc4go/internal/cbus/Reader.go                     |  40 +-
 plc4go/internal/cbus/Reader_test.go                |  35 +-
 plc4go/internal/cbus/Subscriber.go                 |  35 +-
 plc4go/internal/cbus/Writer.go                     |  22 +-
 plc4go/internal/cbus/Writer_test.go                |   6 +-
 .../internal/cbus/mock_RequestTransaction_test.go  |  12 +-
 plc4go/internal/cbus/mock_requirements.go          |   6 +-
 .../{mock_requirements.go => noGlobalLog_test.go}  |  10 +-
 plc4go/internal/eip/Connection.go                  |   5 +-
 plc4go/internal/eip/EipDriver.go                   |   6 +-
 plc4go/internal/eip/Reader.go                      |   7 +-
 plc4go/internal/eip/Writer.go                      |   9 +-
 plc4go/internal/knxnetip/Discoverer.go             |  14 +-
 plc4go/internal/s7/Connection.go                   |   5 +-
 plc4go/internal/s7/Driver.go                       |   6 +-
 plc4go/internal/s7/Reader.go                       |   7 +-
 plc4go/internal/s7/Writer.go                       |   7 +-
 plc4go/pkg/api/driver.go                           |   2 +-
 plc4go/pkg/api/mock_PlcDriver_test.go              |  16 +-
 plc4go/pkg/api/mock_Transport_test.go              |  51 +-
 .../protocols/cbus/readwrite/model/StaticHelper.go |   7 +-
 plc4go/spi/default/DefaultCodec.go                 |  55 +-
 plc4go/spi/default/DefaultConnection.go            |  31 +-
 plc4go/spi/default/DefaultDriver.go                |   2 +-
 .../default/mock_DefaultDriverRequirements_test.go |  16 +-
 plc4go/spi/default/mock_DefaultDriver_test.go      |  16 +-
 plc4go/spi/mock_requirements.go                    |   4 +-
 plc4go/spi/options/Option.go                       |  35 +
 plc4go/spi/pool/mock_CompletionFuture_test.go      | 132 ++++
 plc4go/spi/pool/mock_Executor_test.go              | 248 +++++++
 plc4go/spi/pool/mock_Runnable_test.go              |  84 +++
 plc4go/spi/testutils/TestUtils.go                  |  34 +
 .../spi/transactions/RequestTransactionManager.go  |  85 ++-
 .../transactions/RequestTransactionManager_test.go |  45 +-
 .../mock_RequestTransactionManager_test.go         |  89 ++-
 plc4go/spi/transactions/mock_requirements.go       |   4 +-
 plc4go/spi/transports/Transport.go                 |   7 +-
 plc4go/spi/transports/mock_Transport_test.go       |  50 +-
 plc4go/spi/transports/pcap/Transport.go            |  36 +-
 plc4go/spi/transports/serial/Transport.go          |  35 +-
 plc4go/spi/transports/tcp/Transport.go             |  14 +-
 plc4go/spi/transports/test/Transport.go            |  48 +-
 plc4go/spi/transports/udp/Transport.go             |  23 +-
 59 files changed, 2395 insertions(+), 1112 deletions(-)

diff --git a/plc4go/internal/bacnetip/Connection.go b/plc4go/internal/bacnetip/Connection.go
index 1bc799b950..3c1bff9124 100644
--- a/plc4go/internal/bacnetip/Connection.go
+++ b/plc4go/internal/bacnetip/Connection.go
@@ -22,6 +22,7 @@ package bacnetip
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	"github.com/pkg/errors"
 	"sync"
@@ -40,13 +41,13 @@ type Connection struct {
 	invokeIdGenerator InvokeIdGenerator
 	messageCodec      spi.MessageCodec
 	subscribers       []*Subscriber
-	tm                spi.RequestTransactionManager
+	tm                transactions.RequestTransactionManager
 
 	connectionId string
 	tracer       *spi.Tracer
 }
 
-func NewConnection(messageCodec spi.MessageCodec, tagHandler spi.PlcTagHandler, tm spi.RequestTransactionManager, options map[string][]string) *Connection {
+func NewConnection(messageCodec spi.MessageCodec, tagHandler spi.PlcTagHandler, tm transactions.RequestTransactionManager, options map[string][]string) *Connection {
 	connection := &Connection{
 		invokeIdGenerator: InvokeIdGenerator{currentInvokeId: 0},
 		messageCodec:      messageCodec,
diff --git a/plc4go/internal/bacnetip/Driver.go b/plc4go/internal/bacnetip/Driver.go
index 1315e400c1..6b72a0ccba 100644
--- a/plc4go/internal/bacnetip/Driver.go
+++ b/plc4go/internal/bacnetip/Driver.go
@@ -22,6 +22,7 @@ package bacnetip
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"math"
 	"net"
 	"net/url"
@@ -31,7 +32,6 @@ import (
 	"github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	"github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
-	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
@@ -43,7 +43,7 @@ import (
 type Driver struct {
 	_default.DefaultDriver
 	applicationManager      ApplicationManager
-	tm                      spi.RequestTransactionManager
+	tm                      transactions.RequestTransactionManager
 	awaitSetupComplete      bool
 	awaitDisconnectComplete bool
 }
@@ -53,7 +53,7 @@ func NewDriver() plc4go.PlcDriver {
 		applicationManager: ApplicationManager{
 			applications: map[string]*ApplicationLayerMessageCodec{},
 		},
-		tm:                      spi.NewRequestTransactionManager(math.MaxInt),
+		tm:                      transactions.NewRequestTransactionManager(math.MaxInt),
 		awaitSetupComplete:      true,
 		awaitDisconnectComplete: true,
 	}
diff --git a/plc4go/internal/bacnetip/Reader.go b/plc4go/internal/bacnetip/Reader.go
index 3fdc4961ed..e8e1f5b1cc 100644
--- a/plc4go/internal/bacnetip/Reader.go
+++ b/plc4go/internal/bacnetip/Reader.go
@@ -22,6 +22,7 @@ package bacnetip
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"time"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
@@ -37,13 +38,13 @@ import (
 type Reader struct {
 	invokeIdGenerator *InvokeIdGenerator
 	messageCodec      spi.MessageCodec
-	tm                spi.RequestTransactionManager
+	tm                transactions.RequestTransactionManager
 
 	maxSegmentsAccepted   readWriteModel.MaxSegmentsAccepted
 	maxApduLengthAccepted readWriteModel.MaxApduLengthAccepted
 }
 
-func NewReader(invokeIdGenerator *InvokeIdGenerator, messageCodec spi.MessageCodec, tm spi.RequestTransactionManager) *Reader {
+func NewReader(invokeIdGenerator *InvokeIdGenerator, messageCodec spi.MessageCodec, tm transactions.RequestTransactionManager) *Reader {
 	return &Reader{
 		invokeIdGenerator: invokeIdGenerator,
 		messageCodec:      messageCodec,
@@ -126,7 +127,7 @@ func (m *Reader) Read(ctx context.Context, readRequest apiModel.PlcReadRequest)
 
 		// Start a new request-transaction (Is ended in the response-handler)
 		transaction := m.tm.StartTransaction()
-		transaction.Submit(func(transaction spi.RequestTransaction) {
+		transaction.Submit(func(transaction transactions.RequestTransaction) {
 			// Send the  over the wire
 			log.Trace().Msg("Send ")
 			if err := m.messageCodec.SendRequest(ctx, apdu, func(message spi.Message) bool {
diff --git a/plc4go/internal/cbus/Browser.go b/plc4go/internal/cbus/Browser.go
index 56c4ed7af8..e0a83358c2 100644
--- a/plc4go/internal/cbus/Browser.go
+++ b/plc4go/internal/cbus/Browser.go
@@ -22,29 +22,34 @@ package cbus
 import (
 	"context"
 	"fmt"
-	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
 	"time"
 
+	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	"github.com/apache/plc4x/plc4go/pkg/api/values"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
+	"github.com/apache/plc4x/plc4go/spi/options"
 
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
+	"github.com/rs/zerolog"
 )
 
 type Browser struct {
 	_default.DefaultBrowser
 	connection      plc4go.PlcConnection
 	sequenceCounter uint8
+
+	log zerolog.Logger
 }
 
-func NewBrowser(connection plc4go.PlcConnection) *Browser {
+func NewBrowser(connection plc4go.PlcConnection, _options ...options.WithOption) *Browser {
 	browser := Browser{
 		connection:      connection,
 		sequenceCounter: 0,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 	browser.DefaultBrowser = _default.NewDefaultBrowser(browser)
 	return &browser
@@ -56,36 +61,36 @@ func (m Browser) BrowseQuery(ctx context.Context, interceptor func(result apiMod
 	case *unitInfoQuery:
 		units, allUnits, err := m.extractUnits(ctx, query, m.getInstalledUnitAddressBytes)
 		if err != nil {
-			log.Error().Err(err).Msg("Error extracting units")
+			m.log.Error().Err(err).Msg("Error extracting units")
 			return apiModel.PlcResponseCode_INTERNAL_ERROR, nil
 		}
 		attributes, allAttributes := m.extractAttributes(query)
 
 		if allUnits {
-			log.Info().Msg("Querying all (available) units")
+			m.log.Info().Msg("Querying all (available) units")
 		}
 	unitLoop:
 		for _, unit := range units {
 			if err := ctx.Err(); err != nil {
-				log.Info().Err(err).Msgf("Aborting scan at unit %s", unit)
+				m.log.Info().Err(err).Msgf("Aborting scan at unit %s", unit)
 				return apiModel.PlcResponseCode_INVALID_ADDRESS, nil
 			}
 			unitAddress := unit.GetAddress()
 			if !allUnits && allAttributes {
-				log.Info().Msgf("Querying all attributes of unit %d", unitAddress)
+				m.log.Info().Msgf("Querying all attributes of unit %d", unitAddress)
 			}
-			event := log.Info()
+			event := m.log.Info()
 			if allUnits {
-				event = log.Debug()
+				event = m.log.Debug()
 			}
 			event.Msgf("Query unit  %d", unitAddress)
 			for _, attribute := range attributes {
 				if err := ctx.Err(); err != nil {
-					log.Info().Err(err).Msgf("Aborting scan at unit %s", unit)
+					m.log.Info().Err(err).Msgf("Aborting scan at unit %s", unit)
 					return apiModel.PlcResponseCode_INVALID_ADDRESS, nil
 				}
 				if !allUnits && !allAttributes {
-					log.Info().Msgf("Querying attribute %s of unit %d", attribute, unitAddress)
+					m.log.Info().Msgf("Querying attribute %s of unit %d", attribute, unitAddress)
 				} else {
 					event.Msgf("unit %d: Query %s", unitAddress, attribute)
 				}
@@ -195,45 +200,45 @@ func (m Browser) getInstalledUnitAddressBytes(ctx context.Context) (map[byte]any
 	result := make(map[byte]any)
 	plcConsumerRegistration := subscriptionHandle.Register(func(event apiModel.PlcSubscriptionEvent) {
 		if responseCode := event.GetResponseCode("installationMMIMonitor"); responseCode != apiModel.PlcResponseCode_OK {
-			log.Warn().Msgf("Ignoring %v", event)
+			m.log.Warn().Msgf("Ignoring %v", event)
 			return
 		}
 		rootValue := event.GetValue("installationMMIMonitor")
 		if !rootValue.IsStruct() {
-			log.Warn().Msgf("Ignoring %v should be a struct", rootValue)
+			m.log.Warn().Msgf("Ignoring %v should be a struct", rootValue)
 			return
 		}
 		rootStruct := rootValue.GetStruct()
 		if applicationValue := rootStruct["application"]; applicationValue == nil || !applicationValue.IsString() || applicationValue.GetString() != "NETWORK_CONTROL" {
-			log.Warn().Msgf("Ignoring %v should contain a application tag of type string with value NETWORK_CONTROL", rootStruct)
+			m.log.Warn().Msgf("Ignoring %v should contain a application tag of type string with value NETWORK_CONTROL", rootStruct)
 			return
 		}
 		var blockStart int
 		if blockStartValue := rootStruct["blockStart"]; blockStartValue == nil || !blockStartValue.IsByte() {
-			log.Warn().Msgf("Ignoring %v should contain a blockStart tag of type byte", rootStruct)
+			m.log.Warn().Msgf("Ignoring %v should contain a blockStart tag of type byte", rootStruct)
 			return
 		} else {
 			blockStart = int(blockStartValue.GetByte())
 		}
 
 		if plcListValue := rootStruct["values"]; plcListValue == nil || !plcListValue.IsList() {
-			log.Warn().Msgf("Ignoring %v should contain a values tag of type list", rootStruct)
+			m.log.Warn().Msgf("Ignoring %v should contain a values tag of type list", rootStruct)
 			return
 		} else {
 			for unitByteAddress, plcValue := range plcListValue.GetList() {
 				unitByteAddress = blockStart + unitByteAddress
 				if !plcValue.IsString() {
-					log.Warn().Msgf("Ignoring %v at %d should be a string", plcValue, unitByteAddress)
+					m.log.Warn().Msgf("Ignoring %v at %d should be a string", plcValue, unitByteAddress)
 					return
 				}
 				switch plcValue.GetString() {
 				case readWriteModel.GAVState_ON.PLC4XEnumName(), readWriteModel.GAVState_OFF.PLC4XEnumName():
-					log.Debug().Msgf("unit %d does exists", unitByteAddress)
+					m.log.Debug().Msgf("unit %d does exists", unitByteAddress)
 					result[byte(unitByteAddress)] = true
 				case readWriteModel.GAVState_DOES_NOT_EXIST.PLC4XEnumName():
-					log.Debug().Msgf("unit %d does not exists", unitByteAddress)
+					m.log.Debug().Msgf("unit %d does not exists", unitByteAddress)
 				case readWriteModel.GAVState_ERROR.PLC4XEnumName():
-					log.Warn().Msgf("unit %d is in error state", unitByteAddress)
+					m.log.Warn().Msgf("unit %d is in error state", unitByteAddress)
 				}
 			}
 		}
@@ -268,52 +273,52 @@ func (m Browser) getInstalledUnitAddressBytes(ctx context.Context) (map[byte]any
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				m.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
 		defer readCtxCancel()
 		readRequestResult := <-readRequest.ExecuteWithContext(readCtx)
 		if err := readRequestResult.GetErr(); err != nil {
-			log.Warn().Err(err).Msg("Error reading the mmi")
+			m.log.Warn().Err(err).Msg("Error reading the mmi")
 			return
 		}
 		if responseCode := readRequestResult.GetResponse().GetResponseCode("installationMMI"); responseCode == apiModel.PlcResponseCode_OK {
 			rootValue := readRequestResult.GetResponse().GetValue("installationMMI")
 			if !rootValue.IsStruct() {
-				log.Warn().Err(err).Msgf("%v should be a struct", rootValue)
+				m.log.Warn().Err(err).Msgf("%v should be a struct", rootValue)
 				return
 			}
 			rootStruct := rootValue.GetStruct()
 			if applicationValue := rootStruct["application"]; applicationValue == nil || !applicationValue.IsString() || applicationValue.GetString() != "NETWORK_CONTROL" {
-				log.Warn().Err(err).Msgf("%v should contain a application tag of type string with value NETWORK_CONTROL", rootStruct)
+				m.log.Warn().Err(err).Msgf("%v should contain a application tag of type string with value NETWORK_CONTROL", rootStruct)
 				return
 			}
 			var blockStart int
 			if blockStartValue := rootStruct["blockStart"]; blockStartValue == nil || !blockStartValue.IsByte() || blockStartValue.GetByte() != 0 {
-				log.Warn().Err(err).Msgf("%v should contain a blockStart tag of type byte with value 0", rootStruct)
+				m.log.Warn().Err(err).Msgf("%v should contain a blockStart tag of type byte with value 0", rootStruct)
 				return
 			} else {
 				blockStart = int(blockStartValue.GetByte())
 			}
 
 			if plcListValue := rootStruct["values"]; plcListValue == nil || !plcListValue.IsList() {
-				log.Warn().Err(err).Msgf("%v should contain a values tag of type list", rootStruct)
+				m.log.Warn().Err(err).Msgf("%v should contain a values tag of type list", rootStruct)
 				return
 			} else {
 				for unitByteAddress, plcValue := range plcListValue.GetList() {
 					unitByteAddress = blockStart + unitByteAddress
 					if !plcValue.IsString() {
-						log.Warn().Err(err).Msgf("%v at %d should be a string", plcValue, unitByteAddress)
+						m.log.Warn().Err(err).Msgf("%v at %d should be a string", plcValue, unitByteAddress)
 						return
 					}
 					switch plcValue.GetString() {
 					case readWriteModel.GAVState_ON.PLC4XEnumName(), readWriteModel.GAVState_OFF.PLC4XEnumName():
-						log.Debug().Msgf("unit %d does exists", unitByteAddress)
+						m.log.Debug().Msgf("unit %d does exists", unitByteAddress)
 						result[byte(unitByteAddress)] = true
 					case readWriteModel.GAVState_DOES_NOT_EXIST.PLC4XEnumName():
-						log.Debug().Msgf("unit %d does not exists", unitByteAddress)
+						m.log.Debug().Msgf("unit %d does not exists", unitByteAddress)
 					case readWriteModel.GAVState_ERROR.PLC4XEnumName():
-						log.Warn().Msgf("unit %d is in error state", unitByteAddress)
+						m.log.Warn().Msgf("unit %d is in error state", unitByteAddress)
 					}
 				}
 			}
@@ -327,7 +332,7 @@ func (m Browser) getInstalledUnitAddressBytes(ctx context.Context) (map[byte]any
 			}
 
 		} else {
-			log.Warn().Msgf("We got %s as response code for installation mmi so we rely on getting it via subscription", responseCode)
+			m.log.Warn().Msgf("We got %s as response code for installation mmi so we rely on getting it via subscription", responseCode)
 		}
 	}()
 
@@ -336,13 +341,13 @@ func (m Browser) getInstalledUnitAddressBytes(ctx context.Context) (map[byte]any
 	for !blockOffset0Received || !blockOffset88Received || !blockOffset176Received {
 		select {
 		case <-blockOffset0ReceivedChan:
-			log.Trace().Msg("Offset 0 received")
+			m.log.Trace().Msg("Offset 0 received")
 			blockOffset0Received = true
 		case <-blockOffset88ReceivedChan:
-			log.Trace().Msg("Offset 88 received")
+			m.log.Trace().Msg("Offset 88 received")
 			blockOffset88Received = true
 		case <-blockOffset176ReceivedChan:
-			log.Trace().Msg("Offset 176 received")
+			m.log.Trace().Msg("Offset 176 received")
 			blockOffset176Received = true
 		case <-syncCtx.Done():
 			return nil, errors.Wrap(err, "error waiting for other offsets")
diff --git a/plc4go/internal/cbus/Browser_test.go b/plc4go/internal/cbus/Browser_test.go
index f6cc485c38..f14cba80ac 100644
--- a/plc4go/internal/cbus/Browser_test.go
+++ b/plc4go/internal/cbus/Browser_test.go
@@ -22,20 +22,25 @@ package cbus
 import (
 	"context"
 	"fmt"
+	"net/url"
+	"sync/atomic"
+	"testing"
+
 	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/transports/test"
 	spiValues "github.com/apache/plc4x/plc4go/spi/values"
+
 	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 	"github.com/stretchr/testify/assert"
-	"net/url"
-	"sync/atomic"
-	"testing"
 )
 
 func TestNewBrowser(t *testing.T) {
@@ -47,6 +52,7 @@ func TestBrowser_BrowseQuery(t *testing.T) {
 		DefaultBrowser  _default.DefaultBrowser
 		connection      plc4go.PlcConnection
 		sequenceCounter uint8
+		log             zerolog.Logger
 	}
 	type args struct {
 		ctx         context.Context
@@ -58,6 +64,7 @@ func TestBrowser_BrowseQuery(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 		want   apiModel.PlcResponseCode
 		want1  []apiModel.PlcBrowseItem
 	}{
@@ -67,88 +74,6 @@ func TestBrowser_BrowseQuery(t *testing.T) {
 		},
 		{
 			name: "non responding browse",
-			fields: fields{
-				DefaultBrowser: nil,
-				connection: func() plc4go.PlcConnection {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						APPLICATION_FILTER_1
-						APPLICATION_FILTER_2
-						INTERFACE_OPTIONS_3
-						INTERFACE_OPTIONS_1_PUN
-						INTERFACE_OPTIONS_1
-						MANUFACTURER
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(APPLICATION_FILTER_1)
-						case APPLICATION_FILTER_1:
-							t.Log("Dispatching app1 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
-							transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
-							currentState.Store(APPLICATION_FILTER_2)
-						case APPLICATION_FILTER_2:
-							t.Log("Dispatching app2 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
-							transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_3)
-						case INTERFACE_OPTIONS_3:
-							t.Log("Dispatching interface 3 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A342000A\r"))
-							transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_1_PUN)
-						case INTERFACE_OPTIONS_1_PUN:
-							t.Log("Dispatching interface 1 PUN echo and confirm???")
-							transportInstance.FillReadBuffer([]byte("@A3410079\r"))
-							transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_1)
-						case INTERFACE_OPTIONS_1:
-							t.Log("Dispatching interface 1 echo and confirm???")
-							transportInstance.FillReadBuffer([]byte("@A3300079\r"))
-							transportInstance.FillReadBuffer([]byte("3230009E\r\n"))
-							currentState.Store(MANUFACTURER)
-						case MANUFACTURER:
-							t.Log("Dispatching manufacturer")
-							transportInstance.FillReadBuffer([]byte("g.890050435F434E49454422\r\n"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Dispatching 3 MMI segments")
-							transportInstance.FillReadBuffer([]byte("86020200F900FF0094120006000000000000000008000000000000000000CA\r\n"))
-							transportInstance.FillReadBuffer([]byte("86020200F900FF580000000000000000000000000000000000000000000026\r\n"))
-							transportInstance.FillReadBuffer([]byte("86020200F700FFB00000000000000000000000000000000000000000D0\r\n"))
-						}
-					})
-					err = transport.AddPreregisteredInstances(transportUrl, transportInstance)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					connectionConnectResult := <-NewDriver().GetConnection(transportUrl, map[string]transports.Transport{"test": transport}, map[string][]string{})
-					if err := connectionConnectResult.GetErr(); err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return connectionConnectResult.GetConnection()
-				}(),
-				sequenceCounter: 0,
-			},
 			args: args{
 				ctx: context.Background(),
 				interceptor: func(result apiModel.PlcBrowseItem) bool {
@@ -158,6 +83,91 @@ func TestBrowser_BrowseQuery(t *testing.T) {
 				queryName: "testQuery",
 				query:     NewUnitInfoQuery(readWriteModel.NewUnitAddress(2), nil, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				// Set the model logger to the logger above
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					APPLICATION_FILTER_1
+					APPLICATION_FILTER_2
+					INTERFACE_OPTIONS_3
+					INTERFACE_OPTIONS_1_PUN
+					INTERFACE_OPTIONS_1
+					MANUFACTURER
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(APPLICATION_FILTER_1)
+					case APPLICATION_FILTER_1:
+						t.Log("Dispatching app1 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
+						transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
+						currentState.Store(APPLICATION_FILTER_2)
+					case APPLICATION_FILTER_2:
+						t.Log("Dispatching app2 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
+						transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_3)
+					case INTERFACE_OPTIONS_3:
+						t.Log("Dispatching interface 3 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A342000A\r"))
+						transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_1_PUN)
+					case INTERFACE_OPTIONS_1_PUN:
+						t.Log("Dispatching interface 1 PUN echo and confirm???")
+						transportInstance.FillReadBuffer([]byte("@A3410079\r"))
+						transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_1)
+					case INTERFACE_OPTIONS_1:
+						t.Log("Dispatching interface 1 echo and confirm???")
+						transportInstance.FillReadBuffer([]byte("@A3300079\r"))
+						transportInstance.FillReadBuffer([]byte("3230009E\r\n"))
+						currentState.Store(MANUFACTURER)
+					case MANUFACTURER:
+						t.Log("Dispatching manufacturer")
+						transportInstance.FillReadBuffer([]byte("g.890050435F434E49454422\r\n"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Dispatching 3 MMI segments")
+						transportInstance.FillReadBuffer([]byte("86020200F900FF0094120006000000000000000008000000000000000000CA\r\n"))
+						transportInstance.FillReadBuffer([]byte("86020200F900FF580000000000000000000000000000000000000000000026\r\n"))
+						transportInstance.FillReadBuffer([]byte("86020200F700FFB00000000000000000000000000000000000000000D0\r\n"))
+					}
+				})
+				err = transport.AddPreregisteredInstances(transportUrl, transportInstance)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				connectionConnectResult := <-NewDriver(loggerOption).GetConnection(transportUrl, map[string]transports.Transport{"test": transport}, map[string][]string{})
+				if err := connectionConnectResult.GetErr(); err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				fields.connection = connectionConnectResult.GetConnection()
+			},
 			want: apiModel.PlcResponseCode_OK,
 			want1: []apiModel.PlcBrowseItem{
 				&spiModel.DefaultPlcBrowseItem{
@@ -173,10 +183,14 @@ func TestBrowser_BrowseQuery(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			m := Browser{
 				DefaultBrowser:  tt.fields.DefaultBrowser,
 				connection:      tt.fields.connection,
 				sequenceCounter: tt.fields.sequenceCounter,
+				log:             tt.fields.log,
 			}
 			got, got1 := m.BrowseQuery(tt.args.ctx, tt.args.interceptor, tt.args.queryName, tt.args.query)
 			assert.Equalf(t, tt.want, got, "BrowseQuery(%v, func(), %v,\n%v\n)", tt.args.ctx, tt.args.queryName, tt.args.query)
@@ -190,6 +204,7 @@ func TestBrowser_extractUnits(t *testing.T) {
 		DefaultBrowser  _default.DefaultBrowser
 		connection      plc4go.PlcConnection
 		sequenceCounter uint8
+		log             zerolog.Logger
 	}
 	type args struct {
 		ctx                          context.Context
@@ -247,6 +262,7 @@ func TestBrowser_extractUnits(t *testing.T) {
 				DefaultBrowser:  tt.fields.DefaultBrowser,
 				connection:      tt.fields.connection,
 				sequenceCounter: tt.fields.sequenceCounter,
+				log:             tt.fields.log,
 			}
 			got, got1, err := m.extractUnits(tt.args.ctx, tt.args.query, tt.args.getInstalledUnitAddressBytes)
 			if !tt.wantErr(t, err, fmt.Sprintf("extractUnits(%v, \n%v, func())", tt.args.ctx, tt.args.query)) {
@@ -263,6 +279,7 @@ func TestBrowser_extractAttributes(t *testing.T) {
 		DefaultBrowser  _default.DefaultBrowser
 		connection      plc4go.PlcConnection
 		sequenceCounter uint8
+		log             zerolog.Logger
 	}
 	type args struct {
 		query *unitInfoQuery
@@ -300,6 +317,7 @@ func TestBrowser_extractAttributes(t *testing.T) {
 				DefaultBrowser:  tt.fields.DefaultBrowser,
 				connection:      tt.fields.connection,
 				sequenceCounter: tt.fields.sequenceCounter,
+				log:             tt.fields.log,
 			}
 			got, got1 := m.extractAttributes(tt.args.query)
 			assert.Equalf(t, tt.want, got, "extractAttributes(\n%v)", tt.args.query)
@@ -313,6 +331,7 @@ func TestBrowser_getInstalledUnitAddressBytes(t *testing.T) {
 		DefaultBrowser  _default.DefaultBrowser
 		connection      plc4go.PlcConnection
 		sequenceCounter uint8
+		log             zerolog.Logger
 	}
 	type args struct {
 		ctx context.Context
@@ -321,91 +340,95 @@ func TestBrowser_getInstalledUnitAddressBytes(t *testing.T) {
 		name    string
 		fields  fields
 		args    args
+		setup   func(t *testing.T, fields *fields)
 		want    map[byte]any
 		wantErr assert.ErrorAssertionFunc
 	}{
 		{
 			name: "get units",
-			fields: fields{
-				DefaultBrowser: nil,
-				connection: func() plc4go.PlcConnection {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						APPLICATION_FILTER_1
-						APPLICATION_FILTER_2
-						INTERFACE_OPTIONS_3
-						INTERFACE_OPTIONS_1_PUN
-						INTERFACE_OPTIONS_1
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(APPLICATION_FILTER_1)
-						case APPLICATION_FILTER_1:
-							t.Log("Dispatching app1 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
-							transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
-							currentState.Store(APPLICATION_FILTER_2)
-						case APPLICATION_FILTER_2:
-							t.Log("Dispatching app2 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
-							transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_3)
-						case INTERFACE_OPTIONS_3:
-							t.Log("Dispatching interface 3 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A342000A\r"))
-							transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_1_PUN)
-						case INTERFACE_OPTIONS_1_PUN:
-							t.Log("Dispatching interface 1 PUN echo and confirm???")
-							transportInstance.FillReadBuffer([]byte("@A3410079\r"))
-							transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_1)
-						case INTERFACE_OPTIONS_1:
-							t.Log("Dispatching interface 1 echo and confirm???")
-							transportInstance.FillReadBuffer([]byte("@A3300079\r"))
-							transportInstance.FillReadBuffer([]byte("3230009E\r\n"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Dispatching 3 MMI segments")
-							transportInstance.FillReadBuffer([]byte("86020200F900FF0094120006000000000000000008000000000000000000CA\r\n"))
-							transportInstance.FillReadBuffer([]byte("86020200F900FF580000000000000000000000000000000000000000000026\r\n"))
-							transportInstance.FillReadBuffer([]byte("86020200F700FFB00000000000000000000000000000000000000000D0\r\n"))
-						}
-					})
-					err = transport.AddPreregisteredInstances(transportUrl, transportInstance)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					connectionConnectResult := <-NewDriver().GetConnection(transportUrl, map[string]transports.Transport{"test": transport}, map[string][]string{})
-					if err := connectionConnectResult.GetErr(); err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return connectionConnectResult.GetConnection()
-				}(),
-				sequenceCounter: 0,
-			},
 			args: args{
 				ctx: context.Background(),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				// Set the model logger to the logger above
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					APPLICATION_FILTER_1
+					APPLICATION_FILTER_2
+					INTERFACE_OPTIONS_3
+					INTERFACE_OPTIONS_1_PUN
+					INTERFACE_OPTIONS_1
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(APPLICATION_FILTER_1)
+					case APPLICATION_FILTER_1:
+						t.Log("Dispatching app1 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
+						transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
+						currentState.Store(APPLICATION_FILTER_2)
+					case APPLICATION_FILTER_2:
+						t.Log("Dispatching app2 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
+						transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_3)
+					case INTERFACE_OPTIONS_3:
+						t.Log("Dispatching interface 3 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A342000A\r"))
+						transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_1_PUN)
+					case INTERFACE_OPTIONS_1_PUN:
+						t.Log("Dispatching interface 1 PUN echo and confirm???")
+						transportInstance.FillReadBuffer([]byte("@A3410079\r"))
+						transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_1)
+					case INTERFACE_OPTIONS_1:
+						t.Log("Dispatching interface 1 echo and confirm???")
+						transportInstance.FillReadBuffer([]byte("@A3300079\r"))
+						transportInstance.FillReadBuffer([]byte("3230009E\r\n"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Dispatching 3 MMI segments")
+						transportInstance.FillReadBuffer([]byte("86020200F900FF0094120006000000000000000008000000000000000000CA\r\n"))
+						transportInstance.FillReadBuffer([]byte("86020200F900FF580000000000000000000000000000000000000000000026\r\n"))
+						transportInstance.FillReadBuffer([]byte("86020200F700FFB00000000000000000000000000000000000000000D0\r\n"))
+					}
+				})
+				err = transport.AddPreregisteredInstances(transportUrl, transportInstance)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				connectionConnectResult := <-NewDriver(loggerOption).GetConnection(transportUrl, map[string]transports.Transport{"test": transport}, map[string][]string{})
+				if err := connectionConnectResult.GetErr(); err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				fields.connection = connectionConnectResult.GetConnection()
+			},
 			want: map[byte]any{
 				1:  true,
 				2:  true,
@@ -421,10 +444,14 @@ func TestBrowser_getInstalledUnitAddressBytes(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			m := Browser{
 				DefaultBrowser:  tt.fields.DefaultBrowser,
 				connection:      tt.fields.connection,
 				sequenceCounter: tt.fields.sequenceCounter,
+				log:             tt.fields.log,
 			}
 			got, err := m.getInstalledUnitAddressBytes(tt.args.ctx)
 			if !tt.wantErr(t, err, fmt.Sprintf("getInstalledUnitAddressBytes(%v)", tt.args.ctx)) {
diff --git a/plc4go/internal/cbus/CBusMessageMapper.go b/plc4go/internal/cbus/CBusMessageMapper.go
index a51e604dbf..8e6e0fe4db 100644
--- a/plc4go/internal/cbus/CBusMessageMapper.go
+++ b/plc4go/internal/cbus/CBusMessageMapper.go
@@ -22,9 +22,9 @@ package cbus
 import (
 	"context"
 	"fmt"
-	"github.com/apache/plc4x/plc4go/spi"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	spiValues "github.com/apache/plc4x/plc4go/spi/values"
-	"github.com/rs/zerolog/log"
+	"github.com/rs/zerolog"
 	"strconv"
 	"strings"
 
@@ -277,7 +277,7 @@ func producePointToMultiPointCommandNormal(bridgeAddresses []readWriteModel.Brid
 	return readWriteModel.NewCBusCommandPointToMultiPoint(command, header, cbusOptions), nil
 }
 
-func MapEncodedReply(transaction spi.RequestTransaction, encodedReply readWriteModel.EncodedReply, tagName string, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), addPlcValue func(name string, plcValue apiValues.PlcValue)) error {
+func MapEncodedReply(localLog zerolog.Logger, transaction transactions.RequestTransaction, encodedReply readWriteModel.EncodedReply, tagName string, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), addPlcValue func(name string, plcValue apiValues.PlcValue)) error {
 	switch reply := encodedReply.(type) {
 	case readWriteModel.EncodedReplyCALReplyExactly:
 		calData := reply.GetCalReply().GetCalData()
@@ -479,7 +479,7 @@ func MapEncodedReply(transaction spi.RequestTransaction, encodedReply readWriteM
 		default:
 			wbpcb := spiValues.NewWriteBufferPlcValueBased()
 			if err := calData.SerializeWithWriteBuffer(context.Background(), wbpcb); err != nil {
-				log.Warn().Err(err).Msgf("Unmapped cal data type %T. Returning raw to string", calData)
+				localLog.Warn().Err(err).Msgf("Unmapped cal data type %T. Returning raw to string", calData)
 				addPlcValue(tagName, spiValues.NewPlcSTRING(fmt.Sprintf("%s", calData)))
 			} else {
 				addPlcValue(tagName, wbpcb.GetPlcValue())
diff --git a/plc4go/internal/cbus/CBusMessageMapper_test.go b/plc4go/internal/cbus/CBusMessageMapper_test.go
index 4da9984e32..1067150d48 100644
--- a/plc4go/internal/cbus/CBusMessageMapper_test.go
+++ b/plc4go/internal/cbus/CBusMessageMapper_test.go
@@ -24,7 +24,10 @@ import (
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
-	"github.com/apache/plc4x/plc4go/spi"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/pool"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 	"github.com/stretchr/testify/assert"
@@ -1436,7 +1439,7 @@ func Test_producePointToMultiPointCommandNormal(t *testing.T) {
 
 func TestMapEncodedReply(t *testing.T) {
 	type args struct {
-		transaction     spi.RequestTransaction
+		transaction     transactions.RequestTransaction
 		encodedReply    readWriteModel.EncodedReply
 		tagName         string
 		addResponseCode func(t *testing.T) func(name string, responseCode apiModel.PlcResponseCode)
@@ -1445,19 +1448,12 @@ func TestMapEncodedReply(t *testing.T) {
 	tests := []struct {
 		name    string
 		args    args
+		setup   func(t *testing.T, args *args)
 		wantErr bool
 	}{
 		{
 			name: "empty input",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: nil,
 				tagName:      "",
 				addResponseCode: func(t *testing.T) func(name string, responseCode apiModel.PlcResponseCode) {
@@ -1471,18 +1467,27 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				t.Logf("Submitting No-Op to transaction %v", transaction)
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataStatus",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					statusBytes := []readWriteModel.StatusByte{
 						readWriteModel.NewStatusByte(readWriteModel.GAVState_ON, readWriteModel.GAVState_ERROR, readWriteModel.GAVState_DOES_NOT_EXIST, readWriteModel.GAVState_OFF),
@@ -1533,18 +1538,31 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				t.Logf("Submitting No-Op to transaction %v", transaction)
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+					t.Log("No op-ing")
+				})
+				t.Logf("Submitted to transaction %v", transaction)
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataStatusExtendedExactly (binary)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					statusBytes := []readWriteModel.StatusByte{
 						readWriteModel.NewStatusByte(readWriteModel.GAVState_ON, readWriteModel.GAVState_ERROR, readWriteModel.GAVState_DOES_NOT_EXIST, readWriteModel.GAVState_OFF),
@@ -1595,18 +1613,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataStatusExtendedExactly (level)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					levelInformation := []readWriteModel.LevelInformation{
 						readWriteModel.NewLevelInformationNormal(readWriteModel.LevelInformationNibblePair_Value_A, readWriteModel.LevelInformationNibblePair_Value_F, 13),
@@ -1649,18 +1677,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (sense levels)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandCurrentSenseLevels([]byte{1, 2, 3, 4}, 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_CurrentSenseLevels, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -1693,18 +1731,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (delays)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandDelays([]byte{1, 2, 3, 4}, 5, 5)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_Delays, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -1740,18 +1788,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (dsi status)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandDSIStatus(
 						readWriteModel.ChannelStatus_OK,
@@ -1807,18 +1865,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (extended diagnostic summary)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandExtendedDiagnosticSummary(
 						readWriteModel.ApplicationIdContainer_LIGHTING_3B,
@@ -1892,18 +1960,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (summary)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandSummary("pineapple", 1, "13", 3)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -1940,18 +2018,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (firmware version)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandFirmwareVersion("13", 1)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -1984,18 +2072,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (GAV physical addresses)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandGAVPhysicalAddresses([]byte{1, 2, 3, 4}, 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2028,18 +2126,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (GAV values current)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandGAVValuesCurrent([]byte{1, 2, 3, 4}, 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2072,18 +2180,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (GAV values stored)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandGAVValuesStored([]byte{1, 2, 3, 4}, 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2116,18 +2234,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (logical assignment)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandLogicalAssignment([]readWriteModel.LogicAssignment{
 						readWriteModel.NewLogicAssignment(true, true, true, true, true, true),
@@ -2180,18 +2308,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (manufacturer)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandManufacturer("Apache", 13)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2224,18 +2362,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (maximum levels)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandMaximumLevels([]byte{1, 2, 3, 4}, 1)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2268,18 +2416,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (minimum levels)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandMinimumLevels([]byte{1, 2, 3, 4}, 1)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2312,18 +2470,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (network terminal levels)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandNetworkTerminalLevels([]byte{1, 2, 3, 4}, 1)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2356,18 +2524,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (network voltage)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandNetworkVoltage("13.3", "3", 3)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2400,18 +2578,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (output unit summary)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					gavStoreEnabledByte1 := byte(2)
 					gavStoreEnabledByte2 := byte(3)
@@ -2460,18 +2648,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (terminal levels)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandTerminalLevels([]byte{1, 2, 3, 4}, 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2504,18 +2702,28 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 		{
 			name: "CALDataIdentifyReplyExactly (type)",
 			args: args{
-				transaction: func() spi.RequestTransaction {
-					transactionManager := spi.NewRequestTransactionManager(1)
-					transaction := transactionManager.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
-						// NO-OP
-					})
-					return transaction
-				}(),
 				encodedReply: func() readWriteModel.EncodedReplyCALReply {
 					command := readWriteModel.NewIdentifyReplyCommandType("chonkers", 4)
 					calDataIdentify := readWriteModel.NewCALDataIdentifyReply(readWriteModel.Attribute_DSIStatus, command, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, nil)
@@ -2548,11 +2756,34 @@ func TestMapEncodedReply(t *testing.T) {
 					}
 				},
 			},
+			setup: func(t *testing.T, args *args) {
+				transactionManager := transactions.NewRequestTransactionManager(
+					1,
+					options.WithCustomLogger(testutils.ProduceTestingLogger(t)),
+					transactions.WithCustomExecutor(
+						pool.NewFixedSizeExecutor(10, 50, options.WithCustomLogger(testutils.ProduceTestingLogger(t)), pool.WithExecutorOptionTracerWorkers(true)),
+					),
+				)
+				t.Cleanup(func() {
+					t.Log("Closing transaction manager now")
+					assert.NoError(t, transactionManager.Close())
+				})
+				transaction := transactionManager.StartTransaction()
+				transaction.Submit(func(transaction transactions.RequestTransaction) {
+					// NO-OP
+				})
+				args.transaction = transaction
+			},
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if err := MapEncodedReply(tt.args.transaction, tt.args.encodedReply, tt.args.tagName, tt.args.addResponseCode(t), tt.args.addPlcValue(t)); (err != nil) != tt.wantErr {
+			testingLogger := testutils.ProduceTestingLogger(t)
+			testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+			if tt.setup != nil {
+				tt.setup(t, &tt.args)
+			}
+			if err := MapEncodedReply(testingLogger, tt.args.transaction, tt.args.encodedReply, tt.args.tagName, tt.args.addResponseCode(t), tt.args.addPlcValue(t)); (err != nil) != tt.wantErr {
 				t.Errorf("MapEncodedReply() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})
diff --git a/plc4go/internal/cbus/Configuration.go b/plc4go/internal/cbus/Configuration.go
index 4ec41eaa78..5655c87473 100644
--- a/plc4go/internal/cbus/Configuration.go
+++ b/plc4go/internal/cbus/Configuration.go
@@ -20,11 +20,11 @@
 package cbus
 
 import (
+	"github.com/rs/zerolog"
 	"reflect"
 	"strconv"
 
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type Configuration struct {
@@ -43,13 +43,13 @@ type Configuration struct {
 	MonitoredApplication2 byte
 }
 
-func ParseFromOptions(options map[string][]string) (Configuration, error) {
+func ParseFromOptions(log zerolog.Logger, options map[string][]string) (Configuration, error) {
 	configuration := createDefaultConfiguration()
 	reflectConfiguration := reflect.ValueOf(&configuration).Elem()
 	for i := 0; i < reflectConfiguration.NumField(); i++ {
 		field := reflectConfiguration.Type().Field(i)
 		key := field.Name
-		if optionValue := getFromOptions(options, key); optionValue != "" {
+		if optionValue := getFromOptions(log, options, key); optionValue != "" {
 			switch field.Type.Kind() {
 			case reflect.Uint8:
 				parseUint, err := strconv.ParseUint(optionValue, 0, 8)
@@ -86,13 +86,13 @@ func createDefaultConfiguration() Configuration {
 	}
 }
 
-func getFromOptions(options map[string][]string, key string) string {
+func getFromOptions(localLog zerolog.Logger, options map[string][]string, key string) string {
 	if optionValues, ok := options[key]; ok {
 		if len(optionValues) <= 0 {
 			return ""
 		}
 		if len(optionValues) > 1 {
-			log.Warn().Msgf("Options %s must be unique", key)
+			localLog.Warn().Msgf("Options %s must be unique", key)
 		}
 		return optionValues[0]
 	}
diff --git a/plc4go/internal/cbus/Configuration_test.go b/plc4go/internal/cbus/Configuration_test.go
index b31b0fc176..733d56ce27 100644
--- a/plc4go/internal/cbus/Configuration_test.go
+++ b/plc4go/internal/cbus/Configuration_test.go
@@ -21,6 +21,7 @@ package cbus
 
 import (
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
 	"github.com/stretchr/testify/assert"
 	"testing"
 )
@@ -131,7 +132,7 @@ func TestParseFromOptions(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := ParseFromOptions(tt.args.options)
+			got, err := ParseFromOptions(testutils.ProduceTestingLogger(t), tt.args.options)
 			if !tt.wantErr(t, err, fmt.Sprintf("ParseFromOptions(%v)", tt.args.options)) {
 				return
 			}
@@ -196,7 +197,7 @@ func Test_getFromOptions(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			assert.Equalf(t, tt.want, getFromOptions(tt.args.options, tt.args.key), "getFromOptions(%v, %v)", tt.args.options, tt.args.key)
+			assert.Equalf(t, tt.want, getFromOptions(testutils.ProduceTestingLogger(t), tt.args.options, tt.args.key), "getFromOptions(%v, %v)", tt.args.options, tt.args.key)
 		})
 	}
 }
diff --git a/plc4go/internal/cbus/Connection.go b/plc4go/internal/cbus/Connection.go
index a4935e6c88..858f32ec79 100644
--- a/plc4go/internal/cbus/Connection.go
+++ b/plc4go/internal/cbus/Connection.go
@@ -22,6 +22,9 @@ package cbus
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
+	"github.com/rs/zerolog"
 	"sync"
 	"time"
 
@@ -33,7 +36,6 @@ import (
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type AlphaGenerator struct {
@@ -58,16 +60,18 @@ type Connection struct {
 	alphaGenerator AlphaGenerator
 	messageCodec   *MessageCodec
 	subscribers    []*Subscriber
-	tm             spi.RequestTransactionManager
+	tm             transactions.RequestTransactionManager
 
 	configuration Configuration
 	driverContext DriverContext
 
 	connectionId string
 	tracer       *spi.Tracer
+
+	log zerolog.Logger
 }
 
-func NewConnection(messageCodec *MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm spi.RequestTransactionManager, options map[string][]string) *Connection {
+func NewConnection(messageCodec *MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm transactions.RequestTransactionManager, connectionOptions map[string][]string, _options ...options.WithOption) *Connection {
 	connection := &Connection{
 		alphaGenerator: AlphaGenerator{currentAlpha: 'g'},
 		messageCodec:   messageCodec,
@@ -75,14 +79,17 @@ func NewConnection(messageCodec *MessageCodec, configuration Configuration, driv
 		driverContext:  driverContext,
 		tm:             tm,
 	}
-	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+	if traceEnabledOption, ok := connectionOptions["traceEnabled"]; ok {
 		if len(traceEnabledOption) == 1 {
 			connection.tracer = spi.NewTracer(connection.connectionId)
 		}
 	}
-	connection.DefaultConnection = _default.NewDefaultConnection(connection,
-		_default.WithPlcTagHandler(tagHandler),
-		_default.WithPlcValueHandler(NewValueHandler()),
+	connection.DefaultConnection = _default.NewDefaultConnection(
+		connection,
+		append(_options,
+			_default.WithPlcTagHandler(tagHandler),
+			_default.WithPlcValueHandler(NewValueHandler()),
+		)...,
 	)
 	return connection
 }
@@ -108,7 +115,7 @@ func (c *Connection) GetMessageCodec() spi.MessageCodec {
 }
 
 func (c *Connection) ConnectWithContext(ctx context.Context) <-chan plc4go.PlcConnectionConnectResult {
-	log.Trace().Msg("Connecting")
+	c.log.Trace().Msg("Connecting")
 	ch := make(chan plc4go.PlcConnectionConnectResult)
 	go func() {
 		defer func() {
@@ -124,7 +131,7 @@ func (c *Connection) ConnectWithContext(ctx context.Context) <-chan plc4go.PlcCo
 		// For testing purposes we can skip the waiting for a complete connection
 		if !c.driverContext.awaitSetupComplete {
 			go c.setupConnection(ctx, ch)
-			log.Warn().Msg("Connection used in an unsafe way. !!!DON'T USE IN PRODUCTION!!!")
+			c.log.Warn().Msg("Connection used in an unsafe way. !!!DON'T USE IN PRODUCTION!!!")
 			// Here we write directly and don't wait till the connection is "really" connected
 			// Note: we can't use fireConnected here as it's guarded against m.driverContext.awaitSetupComplete
 			ch <- _default.NewDefaultPlcConnectionConnectResult(c, nil)
@@ -147,7 +154,7 @@ func (c *Connection) GetMetadata() apiModel.PlcConnectionMetadata {
 }
 
 func (c *Connection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
-	return spiModel.NewDefaultPlcReadRequestBuilder(c.GetPlcTagHandler(), NewReader(&c.alphaGenerator, c.messageCodec, c.tm))
+	return spiModel.NewDefaultPlcReadRequestBuilder(c.GetPlcTagHandler(), NewReader(&c.alphaGenerator, c.messageCodec, c.tm, options.WithCustomLogger(c.log)))
 }
 
 func (c *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
@@ -155,7 +162,7 @@ func (c *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
 }
 
 func (c *Connection) SubscriptionRequestBuilder() apiModel.PlcSubscriptionRequestBuilder {
-	return spiModel.NewDefaultPlcSubscriptionRequestBuilder(c.GetPlcTagHandler(), c.GetPlcValueHandler(), NewSubscriber(c))
+	return spiModel.NewDefaultPlcSubscriptionRequestBuilder(c.GetPlcTagHandler(), c.GetPlcValueHandler(), NewSubscriber(c, options.WithCustomLogger(c.log)))
 }
 
 func (c *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRequestBuilder {
@@ -164,13 +171,13 @@ func (c *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRe
 }
 
 func (c *Connection) BrowseRequestBuilder() apiModel.PlcBrowseRequestBuilder {
-	return spiModel.NewDefaultPlcBrowseRequestBuilder(c.GetPlcTagHandler(), NewBrowser(c))
+	return spiModel.NewDefaultPlcBrowseRequestBuilder(c.GetPlcTagHandler(), NewBrowser(c, options.WithCustomLogger(c.log)))
 }
 
 func (c *Connection) addSubscriber(subscriber *Subscriber) {
 	for _, sub := range c.subscribers {
 		if sub == subscriber {
-			log.Debug().Msgf("Subscriber %v already added", subscriber)
+			c.log.Debug().Msgf("Subscriber %v already added", subscriber)
 			return
 		}
 	}
@@ -186,27 +193,27 @@ func (c *Connection) setupConnection(ctx context.Context, ch chan plc4go.PlcConn
 	requestContext := &c.messageCodec.requestContext
 
 	if !c.sendReset(ctx, ch, cbusOptions, requestContext, false) {
-		log.Warn().Msg("First reset failed")
+		c.log.Warn().Msg("First reset failed")
 		// We try a second reset in case we get a power up
 		if !c.sendReset(ctx, ch, cbusOptions, requestContext, true) {
-			log.Trace().Msg("Reset failed")
+			c.log.Trace().Msg("Reset failed")
 			return
 		}
 	}
 	if !c.setApplicationFilter(ctx, ch, requestContext, cbusOptions) {
-		log.Trace().Msg("Set application filter failed")
+		c.log.Trace().Msg("Set application filter failed")
 		return
 	}
 	if !c.setInterfaceOptions3(ctx, ch, requestContext, cbusOptions) {
-		log.Trace().Msg("Set interface options 3 failed")
+		c.log.Trace().Msg("Set interface options 3 failed")
 		return
 	}
 	if !c.setInterface1PowerUpSettings(ctx, ch, requestContext, cbusOptions) {
-		log.Trace().Msg("Set interface options 1 power up settings failed")
+		c.log.Trace().Msg("Set interface options 1 power up settings failed")
 		return
 	}
 	if !c.setInterfaceOptions1(ctx, ch, requestContext, cbusOptions) {
-		log.Trace().Msg("Set interface options 1 failed")
+		c.log.Trace().Msg("Set interface options 1 failed")
 		return
 	}
 	c.fireConnected(ch)
@@ -214,50 +221,50 @@ func (c *Connection) setupConnection(ctx context.Context, ch chan plc4go.PlcConn
 }
 
 func (c *Connection) startSubscriptionHandler() {
-	log.Debug().Msg("Starting SAL handler")
+	c.log.Debug().Msg("Starting SAL handler")
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				c.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
-		log.Debug().Msg("SAL handler stated")
+		c.log.Debug().Msg("SAL handler stated")
 		for c.IsConnected() {
 			for monitoredSal := range c.messageCodec.monitoredSALs {
 				for _, subscriber := range c.subscribers {
 					if ok := subscriber.handleMonitoredSAL(monitoredSal); ok {
-						log.Debug().Msgf("%v handled\n%s", subscriber, monitoredSal)
+						c.log.Debug().Msgf("%v handled\n%s", subscriber, monitoredSal)
 						continue
 					}
 				}
 			}
 		}
-		log.Info().Msg("Ending SAL handler")
+		c.log.Info().Msg("Ending SAL handler")
 	}()
-	log.Debug().Msg("Starting MMI handler")
+	c.log.Debug().Msg("Starting MMI handler")
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				c.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
-		log.Debug().Msg("default MMI started")
+		c.log.Debug().Msg("default MMI started")
 		for c.IsConnected() {
 			for calReply := range c.messageCodec.monitoredMMIs {
 				for _, subscriber := range c.subscribers {
 					if ok := subscriber.handleMonitoredMMI(calReply); ok {
-						log.Debug().Msgf("%v handled\n%s", subscriber, calReply)
+						c.log.Debug().Msgf("%v handled\n%s", subscriber, calReply)
 						continue
 					}
 				}
 			}
 		}
-		log.Info().Msg("Ending MMI handler")
+		c.log.Info().Msg("Ending MMI handler")
 	}()
 }
 
 func (c *Connection) sendReset(ctx context.Context, ch chan plc4go.PlcConnectionConnectResult, cbusOptions *readWriteModel.CBusOptions, requestContext *readWriteModel.RequestContext, sendOutErrorNotification bool) (ok bool) {
-	log.Debug().Msgf("Send a reset (sendOutErrorNotification: %t)", sendOutErrorNotification)
+	c.log.Debug().Msgf("Send a reset (sendOutErrorNotification: %t)", sendOutErrorNotification)
 	requestTypeReset := readWriteModel.RequestType_RESET
 	requestReset := readWriteModel.NewRequestReset(requestTypeReset, &requestTypeReset, requestTypeReset, &requestTypeReset, requestTypeReset, nil, &requestTypeReset, requestTypeReset, readWriteModel.NewRequestTermination(), *cbusOptions)
 	cBusMessage := readWriteModel.NewCBusMessageToServer(requestReset, *requestContext, *cbusOptions)
@@ -304,7 +311,7 @@ func (c *Connection) sendReset(ctx context.Context, ch chan plc4go.PlcConnection
 		if sendOutErrorNotification {
 			c.fireConnectionError(errors.Wrap(err, "Error during sending of Reset Request"), ch)
 		} else {
-			log.Warn().Err(err).Msg("connect failed")
+			c.log.Warn().Err(err).Msg("connect failed")
 		}
 		return false
 	}
@@ -314,28 +321,28 @@ func (c *Connection) sendReset(ctx context.Context, ch chan plc4go.PlcConnection
 	defer utils.CleanupTimer(timeout)
 	select {
 	case <-receivedResetEchoChan:
-		log.Debug().Msgf("We received the echo")
+		c.log.Debug().Msgf("We received the echo")
 	case err := <-receivedResetEchoErrorChan:
 		if sendOutErrorNotification {
 			c.fireConnectionError(errors.Wrap(err, "Error receiving of Reset"), ch)
 		} else {
-			log.Trace().Err(err).Msg("connect failed")
+			c.log.Trace().Err(err).Msg("connect failed")
 		}
 		return false
 	case timeout := <-timeout.C:
 		if sendOutErrorNotification {
 			c.fireConnectionError(errors.Errorf("Timeout after %v", timeout.Sub(startTime)), ch)
 		} else {
-			log.Trace().Msgf("Timeout after %v", timeout.Sub(startTime))
+			c.log.Trace().Msgf("Timeout after %v", timeout.Sub(startTime))
 		}
 		return false
 	}
-	log.Debug().Msg("Reset done")
+	c.log.Debug().Msg("Reset done")
 	return true
 }
 
 func (c *Connection) setApplicationFilter(ctx context.Context, ch chan plc4go.PlcConnectionConnectResult, requestContext *readWriteModel.RequestContext, cbusOptions *readWriteModel.CBusOptions) (ok bool) {
-	log.Debug().Msg("Set application filter to all")
+	c.log.Debug().Msg("Set application filter to all")
 	applicationAddress1 := readWriteModel.NewParameterValueApplicationAddress1(readWriteModel.NewApplicationAddress1(c.configuration.MonitoredApplication1), nil, 1)
 	if !c.sendCalDataWrite(ctx, ch, readWriteModel.Parameter_APPLICATION_ADDRESS_1, applicationAddress1, requestContext, cbusOptions) {
 		return false
@@ -344,43 +351,43 @@ func (c *Connection) setApplicationFilter(ctx context.Context, ch chan plc4go.Pl
 	if !c.sendCalDataWrite(ctx, ch, readWriteModel.Parameter_APPLICATION_ADDRESS_2, applicationAddress2, requestContext, cbusOptions) {
 		return false
 	}
-	log.Debug().Msg("Application filter set")
+	c.log.Debug().Msg("Application filter set")
 	return true
 }
 
 func (c *Connection) setInterfaceOptions3(ctx context.Context, ch chan plc4go.PlcConnectionConnectResult, requestContext *readWriteModel.RequestContext, cbusOptions *readWriteModel.CBusOptions) (ok bool) {
-	log.Debug().Msg("Set interface options 3")
+	c.log.Debug().Msg("Set interface options 3")
 	interfaceOptions3 := readWriteModel.NewParameterValueInterfaceOptions3(readWriteModel.NewInterfaceOptions3(c.configuration.Exstat, c.configuration.Pun, c.configuration.LocalSal, c.configuration.Pcn), nil, 1)
 	if !c.sendCalDataWrite(ctx, ch, readWriteModel.Parameter_INTERFACE_OPTIONS_3, interfaceOptions3, requestContext, cbusOptions) {
 		return false
 	}
 	// TODO: add localsal to the options
 	*cbusOptions = readWriteModel.NewCBusOptions(false, false, false, c.configuration.Exstat, false, false, c.configuration.Pun, c.configuration.Pcn, false)
-	log.Debug().Msg("Interface options 3 set")
+	c.log.Debug().Msg("Interface options 3 set")
 	return true
 }
 
 func (c *Connection) setInterface1PowerUpSettings(ctx context.Context, ch chan plc4go.PlcConnectionConnectResult, requestContext *readWriteModel.RequestContext, cbusOptions *readWriteModel.CBusOptions) (ok bool) {
-	log.Debug().Msg("Set interface options 1 power up settings")
+	c.log.Debug().Msg("Set interface options 1 power up settings")
 	interfaceOptions1PowerUpSettings := readWriteModel.NewParameterValueInterfaceOptions1PowerUpSettings(readWriteModel.NewInterfaceOptions1PowerUpSettings(readWriteModel.NewInterfaceOptions1(c.configuration.Idmon, c.configuration.Monitor, c.configuration.Smart, c.configuration.Srchk, c.configuration.XonXoff, c.configuration.Connect)), 1)
 	if !c.sendCalDataWrite(ctx, ch, readWriteModel.Parameter_INTERFACE_OPTIONS_1_POWER_UP_SETTINGS, interfaceOptions1PowerUpSettings, requestContext, cbusOptions) {
 		return false
 	}
 	// TODO: what is with monall
 	*cbusOptions = readWriteModel.NewCBusOptions(c.configuration.Connect, c.configuration.Smart, c.configuration.Idmon, c.configuration.Exstat, c.configuration.Monitor, false, c.configuration.Pun, c.configuration.Pcn, c.configuration.Srchk)
-	log.Debug().Msg("Interface options 1 power up settings set")
+	c.log.Debug().Msg("Interface options 1 power up settings set")
 	return true
 }
 
 func (c *Connection) setInterfaceOptions1(ctx context.Context, ch chan plc4go.PlcConnectionConnectResult, requestContext *readWriteModel.RequestContext, cbusOptions *readWriteModel.CBusOptions) bool {
-	log.Debug().Msg("Set interface options 1")
+	c.log.Debug().Msg("Set interface options 1")
 	interfaceOptions1 := readWriteModel.NewParameterValueInterfaceOptions1(readWriteModel.NewInterfaceOptions1(c.configuration.Idmon, c.configuration.Monitor, c.configuration.Smart, c.configuration.Srchk, c.configuration.XonXoff, c.configuration.Connect), nil, 1)
 	if !c.sendCalDataWrite(ctx, ch, readWriteModel.Parameter_INTERFACE_OPTIONS_1, interfaceOptions1, requestContext, cbusOptions) {
 		return false
 	}
 	// TODO: what is with monall
 	*cbusOptions = readWriteModel.NewCBusOptions(c.configuration.Connect, c.configuration.Smart, c.configuration.Idmon, c.configuration.Exstat, c.configuration.Monitor, false, c.configuration.Pun, c.configuration.Pcn, c.configuration.Srchk)
-	log.Debug().Msg("Interface options 1 set")
+	c.log.Debug().Msg("Interface options 1 set")
 	return true
 }
 
@@ -452,7 +459,7 @@ func (c *Connection) sendCalDataWrite(ctx context.Context, ch chan plc4go.PlcCon
 	defer utils.CleanupTimer(timeout)
 	select {
 	case <-directCommandAckChan:
-		log.Debug().Msgf("We received the ack")
+		c.log.Debug().Msgf("We received the ack")
 	case err := <-directCommandAckErrorChan:
 		c.fireConnectionError(errors.Wrap(err, "Error receiving of ack"), ch)
 		return false
@@ -467,10 +474,10 @@ func (c *Connection) fireConnectionError(err error, ch chan<- plc4go.PlcConnecti
 	if c.driverContext.awaitSetupComplete {
 		ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Error during connection"))
 	} else {
-		log.Error().Err(err).Msg("awaitSetupComplete set to false and we got a error during connect")
+		c.log.Error().Err(err).Msg("awaitSetupComplete set to false and we got a error during connect")
 	}
 	if err := c.messageCodec.Disconnect(); err != nil {
-		log.Debug().Err(err).Msg("Error disconnecting message codec on connection error")
+		c.log.Debug().Err(err).Msg("Error disconnecting message codec on connection error")
 	}
 }
 
@@ -478,7 +485,7 @@ func (c *Connection) fireConnected(ch chan<- plc4go.PlcConnectionConnectResult)
 	if c.driverContext.awaitSetupComplete {
 		ch <- _default.NewDefaultPlcConnectionConnectResult(c, nil)
 	} else {
-		log.Info().Msg("Successfully connected")
+		c.log.Info().Msg("Successfully connected")
 	}
 	c.SetConnected(true)
 }
diff --git a/plc4go/internal/cbus/Connection_test.go b/plc4go/internal/cbus/Connection_test.go
index daff836d99..341a2a275c 100644
--- a/plc4go/internal/cbus/Connection_test.go
+++ b/plc4go/internal/cbus/Connection_test.go
@@ -26,8 +26,12 @@ import (
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/transports/test"
+	"github.com/rs/zerolog"
 	"github.com/stretchr/testify/assert"
 	"net/url"
 	"sync/atomic"
@@ -84,11 +88,12 @@ func TestConnection_BrowseRequestBuilder(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name       string
@@ -116,6 +121,7 @@ func TestConnection_BrowseRequestBuilder(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.True(t, tt.wantAssert(t, c.BrowseRequestBuilder()), "BrowseRequestBuilder()")
 		})
@@ -127,11 +133,12 @@ func TestConnection_ConnectWithContext(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx context.Context
@@ -140,23 +147,12 @@ func TestConnection_ConnectWithContext(t *testing.T) {
 		name         string
 		fields       fields
 		args         args
+		setup        func(t *testing.T, fields *fields)
 		wantAsserter func(*testing.T, <-chan plc4go.PlcConnectionConnectResult) bool
 	}{
 		{
 			name: "just connect and fail",
 			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: NewMessageCodec(func() transports.TransportInstance {
-					transport := test.NewTransport()
-					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-					}
-					return ti
-				}()),
-				subscribers: nil,
-				tm:          nil,
 				configuration: Configuration{
 					Srchk:                 false,
 					Exstat:                false,
@@ -179,6 +175,26 @@ func TestConnection_ConnectWithContext(t *testing.T) {
 				tracer:       nil,
 			},
 			args: args{ctx: context.Background()},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+				fields.messageCodec = NewMessageCodec(func() transports.TransportInstance {
+					transport := test.NewTransport(loggerOption)
+					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil, loggerOption)
+					if err != nil {
+						t.Error(err)
+						t.FailNow()
+					}
+					return ti
+				}(), loggerOption)
+			},
 			wantAsserter: func(t *testing.T, results <-chan plc4go.PlcConnectionConnectResult) bool {
 				assert.NotNil(t, results)
 				result := <-results
@@ -191,6 +207,9 @@ func TestConnection_ConnectWithContext(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -200,6 +219,7 @@ func TestConnection_ConnectWithContext(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.True(t, tt.wantAsserter(t, c.ConnectWithContext(tt.args.ctx)), "ConnectWithContext(%v)", tt.args.ctx)
 		})
@@ -211,11 +231,12 @@ func TestConnection_GetConnection(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name         string
@@ -240,6 +261,7 @@ func TestConnection_GetConnection(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Truef(t, tt.wantAsserter(t, c.GetConnection()), "GetConnection()")
 		})
@@ -251,11 +273,12 @@ func TestConnection_GetConnectionId(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -277,6 +300,7 @@ func TestConnection_GetConnectionId(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.GetConnectionId(), "GetConnectionId()")
 		})
@@ -288,11 +312,12 @@ func TestConnection_GetMessageCodec(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -318,6 +343,7 @@ func TestConnection_GetMessageCodec(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.GetMessageCodec(), "GetMessageCodec()")
 		})
@@ -329,11 +355,12 @@ func TestConnection_GetMetadata(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -362,6 +389,7 @@ func TestConnection_GetMetadata(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.GetMetadata(), "GetMetadata()")
 		})
@@ -373,11 +401,12 @@ func TestConnection_GetTracer(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -399,6 +428,7 @@ func TestConnection_GetTracer(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.GetTracer(), "GetTracer()")
 		})
@@ -410,11 +440,12 @@ func TestConnection_IsTraceEnabled(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -436,6 +467,7 @@ func TestConnection_IsTraceEnabled(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.IsTraceEnabled(), "IsTraceEnabled()")
 		})
@@ -447,11 +479,12 @@ func TestConnection_ReadRequestBuilder(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name       string
@@ -479,6 +512,7 @@ func TestConnection_ReadRequestBuilder(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Truef(t, tt.wantAssert(t, c.ReadRequestBuilder()), "ReadRequestBuilder()")
 		})
@@ -490,11 +524,12 @@ func TestConnection_String(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -517,6 +552,7 @@ func TestConnection_String(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.String(), "String()")
 		})
@@ -528,11 +564,12 @@ func TestConnection_SubscriptionRequestBuilder(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name       string
@@ -560,6 +597,7 @@ func TestConnection_SubscriptionRequestBuilder(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Truef(t, tt.wantAssert(t, c.SubscriptionRequestBuilder()), "SubscriptionRequestBuilder()")
 		})
@@ -571,11 +609,12 @@ func TestConnection_UnsubscriptionRequestBuilder(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
@@ -597,6 +636,7 @@ func TestConnection_UnsubscriptionRequestBuilder(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.UnsubscriptionRequestBuilder(), "UnsubscriptionRequestBuilder()")
 		})
@@ -608,11 +648,12 @@ func TestConnection_WriteRequestBuilder(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name       string
@@ -640,6 +681,7 @@ func TestConnection_WriteRequestBuilder(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Truef(t, tt.wantAssert(t, c.WriteRequestBuilder()), "WriteRequestBuilder()")
 		})
@@ -651,11 +693,12 @@ func TestConnection_addSubscriber(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		subscriber *Subscriber
@@ -694,6 +737,7 @@ func TestConnection_addSubscriber(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			c.addSubscriber(tt.args.subscriber)
 			assert.Truef(t, tt.subElevator(t, c.subscribers), "addSubscriber(%v)", tt.args.subscriber)
@@ -706,11 +750,12 @@ func TestConnection_fireConnected(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ch chan<- plc4go.PlcConnectionConnectResult
@@ -756,6 +801,7 @@ func TestConnection_fireConnected(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			c.fireConnected(tt.args.ch)
 			assert.True(t, tt.chanValidator(t, tt.args.ch))
@@ -768,11 +814,12 @@ func TestConnection_fireConnectionError(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		err error
@@ -837,6 +884,7 @@ func TestConnection_fireConnectionError(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			c.fireConnectionError(tt.args.err, tt.args.ch)
 			assert.True(t, tt.chanValidator(t, tt.args.ch))
@@ -849,11 +897,12 @@ func TestConnection_sendCalDataWrite(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx            context.Context
@@ -867,22 +916,11 @@ func TestConnection_sendCalDataWrite(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 		want   bool
 	}{
 		{
 			name: "send something",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: NewMessageCodec(func() transports.TransportInstance {
-					transport := test.NewTransport()
-					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-					}
-					return ti
-				}()),
-			},
 			args: args{
 				ctx:            context.Background(),
 				ch:             make(chan plc4go.PlcConnectionConnectResult, 1),
@@ -897,11 +935,35 @@ func TestConnection_sendCalDataWrite(t *testing.T) {
 					return &cBusOptions
 				}(),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+				fields.messageCodec = NewMessageCodec(func() transports.TransportInstance {
+					transport := test.NewTransport(loggerOption)
+					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil, loggerOption)
+					if err != nil {
+						t.Error(err)
+						t.FailNow()
+					}
+					return ti
+				}())
+			},
 			want: false,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -911,6 +973,7 @@ func TestConnection_sendCalDataWrite(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.sendCalDataWrite(tt.args.ctx, tt.args.ch, tt.args.paramNo, tt.args.parameterValue, tt.args.requestContext, tt.args.cbusOptions), "sendCalDataWrite(%v, %v, %v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.paramNo, tt.args.parameterValue, tt.args.requestContext, tt.args.cbusOptions)
 		})
@@ -922,11 +985,12 @@ func TestConnection_sendReset(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx                      context.Context
@@ -982,6 +1046,7 @@ func TestConnection_sendReset(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.wantOk, c.sendReset(tt.args.ctx, tt.args.ch, tt.args.cbusOptions, tt.args.requestContext, tt.args.sendOutErrorNotification), "sendReset(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.cbusOptions, tt.args.requestContext, tt.args.sendOutErrorNotification)
 		})
@@ -993,11 +1058,12 @@ func TestConnection_setApplicationFilter(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx            context.Context
@@ -1009,22 +1075,11 @@ func TestConnection_setApplicationFilter(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 		wantOk bool
 	}{
 		{
 			name: "set application filter (failing)",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: NewMessageCodec(func() transports.TransportInstance {
-					transport := test.NewTransport()
-					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-					}
-					return ti
-				}()),
-			},
 			args: args{
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
@@ -1037,11 +1092,36 @@ func TestConnection_setApplicationFilter(t *testing.T) {
 					return &requestContext
 				}(),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Setup connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+				fields.messageCodec = NewMessageCodec(func() transports.TransportInstance {
+					transport := test.NewTransport(loggerOption)
+					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil, loggerOption)
+					if err != nil {
+						t.Error(err)
+						t.FailNow()
+					}
+					return ti
+				}(), loggerOption)
+			},
 			wantOk: false,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -1051,6 +1131,7 @@ func TestConnection_setApplicationFilter(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.wantOk, c.setApplicationFilter(tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions), "setApplicationFilter(%v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions)
 		})
@@ -1062,11 +1143,12 @@ func TestConnection_setInterface1PowerUpSettings(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx            context.Context
@@ -1078,6 +1160,7 @@ func TestConnection_setInterface1PowerUpSettings(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields, args *args)
 		wantOk bool
 	}{
 		{
@@ -1106,11 +1189,17 @@ func TestConnection_setInterface1PowerUpSettings(t *testing.T) {
 					return &requestContext
 				}(),
 			},
+			setup: func(t *testing.T, fields *fields, args *args) {
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+			},
 			wantOk: false,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields, &tt.args)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -1120,6 +1209,7 @@ func TestConnection_setInterface1PowerUpSettings(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.wantOk, c.setInterface1PowerUpSettings(tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions), "setInterface1PowerUpSettings(%v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions)
 		})
@@ -1131,11 +1221,12 @@ func TestConnection_setInterfaceOptions1(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx            context.Context
@@ -1147,6 +1238,7 @@ func TestConnection_setInterfaceOptions1(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 		want   bool
 	}{
 		{
@@ -1175,11 +1267,17 @@ func TestConnection_setInterfaceOptions1(t *testing.T) {
 					return &requestContext
 				}(),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+			},
 			want: false,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -1189,6 +1287,7 @@ func TestConnection_setInterfaceOptions1(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.want, c.setInterfaceOptions1(tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions), "setInterfaceOptions1(%v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions)
 		})
@@ -1200,11 +1299,12 @@ func TestConnection_setInterfaceOptions3(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx            context.Context
@@ -1216,6 +1316,7 @@ func TestConnection_setInterfaceOptions3(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 		wantOk bool
 	}{
 		{
@@ -1244,11 +1345,17 @@ func TestConnection_setInterfaceOptions3(t *testing.T) {
 					return &requestContext
 				}(),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+			},
 			wantOk: false,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -1258,6 +1365,7 @@ func TestConnection_setInterfaceOptions3(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			assert.Equalf(t, tt.wantOk, c.setInterfaceOptions3(tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions), "setInterfaceOptions3(%v, %v, %v, %v)", tt.args.ctx, tt.args.ch, tt.args.requestContext, tt.args.cbusOptions)
 		})
@@ -1269,11 +1377,12 @@ func TestConnection_setupConnection(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	type args struct {
 		ctx context.Context
@@ -1283,12 +1392,29 @@ func TestConnection_setupConnection(t *testing.T) {
 		name   string
 		fields fields
 		args   args
+		setup  func(t *testing.T, fields *fields)
 	}{
 		{
 			name: "setup connection (failing)",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: NewMessageCodec(func() transports.TransportInstance {
+			args: args{
+				ctx: context.Background(),
+				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
+			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				fields.messageCodec = NewMessageCodec(func() transports.TransportInstance {
 					transport := test.NewTransport()
 					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil)
 					if err != nil {
@@ -1296,246 +1422,277 @@ func TestConnection_setupConnection(t *testing.T) {
 						t.FailNow()
 					}
 					return ti
-				}()),
-			},
-			args: args{
-				ctx: context.Background(),
-				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
+				}(), loggerOption)
 			},
 		},
 		{
 			name: "setup connection (failing after reset)",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: func() *MessageCodec {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Done")
-						}
-					})
-					codec := NewMessageCodec(transportInstance)
-					err = codec.Connect()
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return codec
-				}(),
-			},
 			args: args{
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Done")
+					}
+				})
+				codec := NewMessageCodec(transportInstance, loggerOption)
+				err = codec.Connect()
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+
+				fields.messageCodec = codec
+			},
 		},
 		{
 			name: "setup connection (failing after app filters)",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: func() *MessageCodec {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						APPLICATION_FILTER_1
-						APPLICATION_FILTER_2
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(APPLICATION_FILTER_1)
-						case APPLICATION_FILTER_1:
-							t.Log("Dispatching app1 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
-							transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
-							currentState.Store(APPLICATION_FILTER_2)
-						case APPLICATION_FILTER_2:
-							t.Log("Dispatching app2 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
-							transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Done")
-						}
-					})
-					codec := NewMessageCodec(transportInstance)
-					err = codec.Connect()
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return codec
-				}(),
-			},
 			args: args{
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					APPLICATION_FILTER_1
+					APPLICATION_FILTER_2
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(APPLICATION_FILTER_1)
+					case APPLICATION_FILTER_1:
+						t.Log("Dispatching app1 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
+						transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
+						currentState.Store(APPLICATION_FILTER_2)
+					case APPLICATION_FILTER_2:
+						t.Log("Dispatching app2 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
+						transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Done")
+					}
+				})
+				codec := NewMessageCodec(transportInstance, loggerOption)
+				err = codec.Connect()
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+
+				fields.messageCodec = codec
+			},
 		},
 		{
 			name: "setup connection (failing after interface options 3",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: func() *MessageCodec {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						APPLICATION_FILTER_1
-						APPLICATION_FILTER_2
-						INTERFACE_OPTIONS_3
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(APPLICATION_FILTER_1)
-						case APPLICATION_FILTER_1:
-							t.Log("Dispatching app1 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
-							transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
-							currentState.Store(APPLICATION_FILTER_2)
-						case APPLICATION_FILTER_2:
-							t.Log("Dispatching app2 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
-							transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_3)
-						case INTERFACE_OPTIONS_3:
-							t.Log("Dispatching interface 3 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A342000A\r"))
-							transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Done")
-						}
-					})
-					codec := NewMessageCodec(transportInstance)
-					err = codec.Connect()
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return codec
-				}(),
-			},
 			args: args{
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					APPLICATION_FILTER_1
+					APPLICATION_FILTER_2
+					INTERFACE_OPTIONS_3
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(APPLICATION_FILTER_1)
+					case APPLICATION_FILTER_1:
+						t.Log("Dispatching app1 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
+						transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
+						currentState.Store(APPLICATION_FILTER_2)
+					case APPLICATION_FILTER_2:
+						t.Log("Dispatching app2 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
+						transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_3)
+					case INTERFACE_OPTIONS_3:
+						t.Log("Dispatching interface 3 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A342000A\r"))
+						transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Done")
+					}
+				})
+				codec := NewMessageCodec(transportInstance, loggerOption)
+				err = codec.Connect()
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+
+				fields.messageCodec = codec
+			},
 		},
 		{
 			name: "setup connection (failing after interface options 1 pun)",
-			fields: fields{
-				DefaultConnection: _default.NewDefaultConnection(nil),
-				messageCodec: func() *MessageCodec {
-					transport := test.NewTransport()
-					transportUrl := url.URL{Scheme: "test"}
-					transportInstance, err := transport.CreateTransportInstance(transportUrl, nil)
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					type MockState uint8
-					const (
-						RESET MockState = iota
-						APPLICATION_FILTER_1
-						APPLICATION_FILTER_2
-						INTERFACE_OPTIONS_3
-						INTERFACE_OPTIONS_1_PUN
-						DONE
-					)
-					currentState := atomic.Value{}
-					currentState.Store(RESET)
-					transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
-						switch currentState.Load().(MockState) {
-						case RESET:
-							t.Log("Dispatching reset echo")
-							transportInstance.FillReadBuffer([]byte("~~~\r"))
-							currentState.Store(APPLICATION_FILTER_1)
-						case APPLICATION_FILTER_1:
-							t.Log("Dispatching app1 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
-							transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
-							currentState.Store(APPLICATION_FILTER_2)
-						case APPLICATION_FILTER_2:
-							t.Log("Dispatching app2 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
-							transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_3)
-						case INTERFACE_OPTIONS_3:
-							t.Log("Dispatching interface 3 echo and confirm")
-							transportInstance.FillReadBuffer([]byte("@A342000A\r"))
-							transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
-							currentState.Store(INTERFACE_OPTIONS_1_PUN)
-						case INTERFACE_OPTIONS_1_PUN:
-							t.Log("Dispatching interface 1 PUN echo and confirm???")
-							transportInstance.FillReadBuffer([]byte("@A3410079\r"))
-							transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
-							currentState.Store(DONE)
-						case DONE:
-							t.Log("Done")
-						}
-					})
-					codec := NewMessageCodec(transportInstance)
-					err = codec.Connect()
-					if err != nil {
-						t.Error(err)
-						t.FailNow()
-						return nil
-					}
-					return codec
-				}(),
-			},
 			args: args{
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				transport := test.NewTransport(loggerOption)
+				transportUrl := url.URL{Scheme: "test"}
+				transportInstance, err := transport.CreateTransportInstance(transportUrl, nil, loggerOption)
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				type MockState uint8
+				const (
+					RESET MockState = iota
+					APPLICATION_FILTER_1
+					APPLICATION_FILTER_2
+					INTERFACE_OPTIONS_3
+					INTERFACE_OPTIONS_1_PUN
+					DONE
+				)
+				currentState := atomic.Value{}
+				currentState.Store(RESET)
+				transportInstance.(*test.TransportInstance).SetWriteInterceptor(func(transportInstance *test.TransportInstance, data []byte) {
+					switch currentState.Load().(MockState) {
+					case RESET:
+						t.Log("Dispatching reset echo")
+						transportInstance.FillReadBuffer([]byte("~~~\r"))
+						currentState.Store(APPLICATION_FILTER_1)
+					case APPLICATION_FILTER_1:
+						t.Log("Dispatching app1 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32100FF\r"))
+						transportInstance.FillReadBuffer([]byte("322100AD\r\n"))
+						currentState.Store(APPLICATION_FILTER_2)
+					case APPLICATION_FILTER_2:
+						t.Log("Dispatching app2 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A32200FF\r"))
+						transportInstance.FillReadBuffer([]byte("322200AC\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_3)
+					case INTERFACE_OPTIONS_3:
+						t.Log("Dispatching interface 3 echo and confirm")
+						transportInstance.FillReadBuffer([]byte("@A342000A\r"))
+						transportInstance.FillReadBuffer([]byte("3242008C\r\n"))
+						currentState.Store(INTERFACE_OPTIONS_1_PUN)
+					case INTERFACE_OPTIONS_1_PUN:
+						t.Log("Dispatching interface 1 PUN echo and confirm???")
+						transportInstance.FillReadBuffer([]byte("@A3410079\r"))
+						transportInstance.FillReadBuffer([]byte("3241008D\r\n"))
+						currentState.Store(DONE)
+					case DONE:
+						t.Log("Done")
+					}
+				})
+				codec := NewMessageCodec(transportInstance, loggerOption)
+				err = codec.Connect()
+				if err != nil {
+					t.Error(err)
+					t.FailNow()
+				}
+				fields.messageCodec = codec
+			},
 		},
 		{
 			name: "setup connection",
@@ -1611,10 +1768,37 @@ func TestConnection_setupConnection(t *testing.T) {
 				ctx: context.Background(),
 				ch:  make(chan plc4go.PlcConnectionConnectResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				// Setup logger
+				logger := testutils.ProduceTestingLogger(t)
+				fields.log = logger
+
+				testutils.SetToTestingLogger(t, readWriteModel.Plc4xModelLog)
+
+				// Custom option for that
+				loggerOption := options.WithCustomLogger(logger)
+
+				// Build the default connection
+				fields.DefaultConnection = _default.NewDefaultConnection(nil, loggerOption)
+
+				// Build the message codec
+				fields.messageCodec = NewMessageCodec(func() transports.TransportInstance {
+					transport := test.NewTransport()
+					ti, err := transport.CreateTransportInstance(url.URL{Scheme: "test"}, nil)
+					if err != nil {
+						t.Error(err)
+						t.FailNow()
+					}
+					return ti
+				}(), loggerOption)
+			},
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			c := &Connection{
 				DefaultConnection: tt.fields.DefaultConnection,
 				messageCodec:      tt.fields.messageCodec,
@@ -1624,6 +1808,7 @@ func TestConnection_setupConnection(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			c.setupConnection(tt.args.ctx, tt.args.ch)
 		})
@@ -1635,15 +1820,17 @@ func TestConnection_startSubscriptionHandler(t *testing.T) {
 		DefaultConnection _default.DefaultConnection
 		messageCodec      *MessageCodec
 		subscribers       []*Subscriber
-		tm                spi.RequestTransactionManager
+		tm                transactions.RequestTransactionManager
 		configuration     Configuration
 		driverContext     DriverContext
 		connectionId      string
 		tracer            *spi.Tracer
+		log               zerolog.Logger
 	}
 	tests := []struct {
 		name   string
 		fields fields
+		setup  func(t *testing.T, fields *fields)
 	}{
 		{
 			name: "just start",
@@ -1685,7 +1872,9 @@ func TestConnection_startSubscriptionHandler(t *testing.T) {
 					}()
 					return messageCodec
 				}(),
-				subscribers: []*Subscriber{NewSubscriber(nil)},
+			},
+			setup: func(t *testing.T, fields *fields) {
+				fields.subscribers = []*Subscriber{NewSubscriber(nil, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))}
 			},
 		},
 	}
@@ -1700,6 +1889,7 @@ func TestConnection_startSubscriptionHandler(t *testing.T) {
 				driverContext:     tt.fields.driverContext,
 				connectionId:      tt.fields.connectionId,
 				tracer:            tt.fields.tracer,
+				log:               tt.fields.log,
 			}
 			c.startSubscriptionHandler()
 			time.Sleep(50 * time.Millisecond)
@@ -1713,7 +1903,7 @@ func TestNewConnection(t *testing.T) {
 		configuration Configuration
 		driverContext DriverContext
 		tagHandler    spi.PlcTagHandler
-		tm            spi.RequestTransactionManager
+		tm            transactions.RequestTransactionManager
 		options       map[string][]string
 	}
 	tests := []struct {
diff --git a/plc4go/internal/cbus/Discoverer.go b/plc4go/internal/cbus/Discoverer.go
index 1cd681b71e..139ffda597 100644
--- a/plc4go/internal/cbus/Discoverer.go
+++ b/plc4go/internal/cbus/Discoverer.go
@@ -22,6 +22,7 @@ package cbus
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/pool"
 	"github.com/apache/plc4x/plc4go/spi/transports/tcp"
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog"
@@ -43,16 +44,20 @@ import (
 
 type Discoverer struct {
 	transportInstanceCreationWorkItemId atomic.Int32
-	transportInstanceCreationQueue      utils.Executor
+	transportInstanceCreationQueue      pool.Executor
 	deviceScanningWorkItemId            atomic.Int32
-	deviceScanningQueue                 utils.Executor
+	deviceScanningQueue                 pool.Executor
+
+	log zerolog.Logger
 }
 
-func NewDiscoverer() *Discoverer {
+func NewDiscoverer(_options ...options.WithOption) *Discoverer {
 	return &Discoverer{
 		// TODO: maybe a dynamic executor would be better to not waste cycles when not in use
-		transportInstanceCreationQueue: utils.NewFixedSizeExecutor(50, 100),
-		deviceScanningQueue:            utils.NewFixedSizeExecutor(50, 100),
+		transportInstanceCreationQueue: pool.NewFixedSizeExecutor(50, 100, _options...),
+		deviceScanningQueue:            pool.NewFixedSizeExecutor(50, 100, _options...),
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
@@ -61,14 +66,14 @@ func (d *Discoverer) Discover(ctx context.Context, callback func(event apiModel.
 	d.deviceScanningQueue.Start()
 
 	deviceNames := d.extractDeviceNames(discoveryOptions...)
-	interfaces, err := addressProviderRetriever(deviceNames)
+	interfaces, err := addressProviderRetriever(d.log, deviceNames)
 	if err != nil {
 		return errors.Wrap(err, "error getting addresses")
 	}
 	if log.Debug().Enabled() {
 		for _, provider := range interfaces {
-			log.Debug().Msgf("Discover on %s", provider)
-			log.Trace().Msgf("Discover on %#v", provider.containedInterface())
+			d.log.Debug().Msgf("Discover on %s", provider)
+			d.log.Trace().Msgf("Discover on %#v", provider.containedInterface())
 		}
 	}
 
@@ -147,25 +152,25 @@ func (d *Discoverer) Discover(ctx context.Context, callback func(event apiModel.
 	}
 	go func() {
 		wg.Wait()
-		log.Trace().Msg("Closing transport instance channel")
+		d.log.Trace().Msg("Closing transport instance channel")
 		close(transportInstances)
 	}()
 
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				d.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
 		for transportInstance := range transportInstances {
-			log.Debug().Stringer("transportInstance", transportInstance).Msg("submitting device scan")
+			d.log.Debug().Stringer("transportInstance", transportInstance).Msg("submitting device scan")
 			d.deviceScanningQueue.Submit(ctx, d.deviceScanningWorkItemId.Add(1), d.createDeviceScanDispatcher(transportInstance.(*tcp.TransportInstance), callback))
 		}
 	}()
 	return nil
 }
 
-func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *sync.WaitGroup, ip net.IP, tcpTransport *tcp.Transport, transportInstances chan transports.TransportInstance, cBusPort uint16, addressLogger zerolog.Logger) utils.Runnable {
+func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *sync.WaitGroup, ip net.IP, tcpTransport *tcp.Transport, transportInstances chan transports.TransportInstance, cBusPort uint16, addressLogger zerolog.Logger) pool.Runnable {
 	wg.Add(1)
 	return func() {
 		defer wg.Done()
@@ -199,12 +204,12 @@ func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *
 	}
 }
 
-func (d *Discoverer) createDeviceScanDispatcher(tcpTransportInstance *tcp.TransportInstance, callback func(event apiModel.PlcDiscoveryItem)) utils.Runnable {
+func (d *Discoverer) createDeviceScanDispatcher(tcpTransportInstance *tcp.TransportInstance, callback func(event apiModel.PlcDiscoveryItem)) pool.Runnable {
 	return func() {
 		transportInstanceLogger := log.With().Stringer("transportInstance", tcpTransportInstance).Logger()
 		transportInstanceLogger.Debug().Msgf("Scanning %v", tcpTransportInstance)
 		// Create a codec for sending and receiving messages.
-		codec := NewMessageCodec(tcpTransportInstance)
+		codec := NewMessageCodec(tcpTransportInstance, options.WithCustomLogger(d.log))
 		// Explicitly start the worker
 		if err := codec.Connect(); err != nil {
 			transportInstanceLogger.Debug().Err(err).Msg("Error connecting")
@@ -337,12 +342,12 @@ func (w *wrappedInterface) String() string {
 }
 
 // allInterfaceRetriever can be exchanged in tests
-var allInterfaceRetriever = func() ([]addressProvider, error) {
+var allInterfaceRetriever = func(localLog zerolog.Logger) ([]addressProvider, error) {
 	interfaces, err := net.Interfaces()
 	if err != nil {
 		return nil, errors.Wrap(err, "could not retrieve all interfaces")
 	}
-	log.Debug().Msgf("Mapping %d interfaces", len(interfaces))
+	localLog.Debug().Msgf("Mapping %d interfaces", len(interfaces))
 	addressProviders := make([]addressProvider, len(interfaces))
 	for i, networkInterface := range interfaces {
 		var copyInterface = networkInterface
@@ -352,8 +357,8 @@ var allInterfaceRetriever = func() ([]addressProvider, error) {
 }
 
 // addressProviderRetriever can be exchanged in tests
-var addressProviderRetriever = func(deviceNames []string) ([]addressProvider, error) {
-	allInterfaces, err := allInterfaceRetriever()
+var addressProviderRetriever = func(localLog zerolog.Logger, deviceNames []string) ([]addressProvider, error) {
+	allInterfaces, err := allInterfaceRetriever(localLog)
 	if err != nil {
 		return nil, errors.Wrap(err, "error getting all interfaces")
 	}
@@ -362,7 +367,7 @@ var addressProviderRetriever = func(deviceNames []string) ([]addressProvider, er
 	// However if a discovery option is present to select a device by name, only
 	// add those devices matching any of the given names.
 	if len(deviceNames) <= 0 {
-		log.Info().Msgf("no devices selected, use all devices (%d)", len(allInterfaces))
+		localLog.Info().Msgf("no devices selected, use all devices (%d)", len(allInterfaces))
 		return allInterfaces, nil
 	}
 
diff --git a/plc4go/internal/cbus/Discoverer_test.go b/plc4go/internal/cbus/Discoverer_test.go
index d121dbb8fd..2e11686608 100644
--- a/plc4go/internal/cbus/Discoverer_test.go
+++ b/plc4go/internal/cbus/Discoverer_test.go
@@ -24,6 +24,8 @@ import (
 	"fmt"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/pool"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/transports/tcp"
 	"github.com/apache/plc4x/plc4go/spi/utils"
@@ -55,8 +57,8 @@ func TestNewDiscoverer(t *testing.T) {
 
 func TestDiscoverer_Discover(t *testing.T) {
 	type fields struct {
-		transportInstanceCreationQueue utils.Executor
-		deviceScanningQueue            utils.Executor
+		transportInstanceCreationQueue pool.Executor
+		deviceScanningQueue            pool.Executor
 	}
 	type args struct {
 		ctx              context.Context
@@ -68,15 +70,11 @@ func TestDiscoverer_Discover(t *testing.T) {
 		fields   fields
 		args     args
 		wantErr  assert.ErrorAssertionFunc
-		setup    func() (params []any)
+		setup    func(t *testing.T, fields *fields) (params []any)
 		teardown func(params []any)
 	}{
 		{
 			name: "discover unknown device",
-			fields: fields{
-				transportInstanceCreationQueue: utils.NewFixedSizeExecutor(50, 100),
-				deviceScanningQueue:            utils.NewFixedSizeExecutor(50, 100),
-			},
 			args: args{
 				ctx: context.Background(),
 				callback: func(_ apiModel.PlcDiscoveryItem) {
@@ -85,14 +83,15 @@ func TestDiscoverer_Discover(t *testing.T) {
 					options.WithDiscoveryOptionDeviceName("blub"),
 				},
 			},
+			setup: func(t *testing.T, fields *fields) (params []any) {
+				fields.transportInstanceCreationQueue = pool.NewFixedSizeExecutor(50, 100, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+				fields.deviceScanningQueue = pool.NewFixedSizeExecutor(50, 100, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+				return nil
+			},
 			wantErr: assert.NoError,
 		},
 		{
 			name: "test with loopback",
-			fields: fields{
-				transportInstanceCreationQueue: utils.NewFixedSizeExecutor(50, 100),
-				deviceScanningQueue:            utils.NewFixedSizeExecutor(50, 100),
-			},
 			args: args{
 				ctx: context.Background(),
 				callback: func(_ apiModel.PlcDiscoveryItem) {
@@ -102,9 +101,11 @@ func TestDiscoverer_Discover(t *testing.T) {
 				},
 			},
 			wantErr: assert.NoError,
-			setup: func() (params []any) {
+			setup: func(t *testing.T, fields *fields) (params []any) {
+				fields.transportInstanceCreationQueue = pool.NewFixedSizeExecutor(50, 100, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+				fields.deviceScanningQueue = pool.NewFixedSizeExecutor(50, 100, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
 				oldaddressProviderRetriever := addressProviderRetriever
-				addressProviderRetriever = func(_ []string) ([]addressProvider, error) {
+				addressProviderRetriever = func(log zerolog.Logger, _ []string) ([]addressProvider, error) {
 					loopbackInterface, err := nettest.LoopbackInterface()
 					if err != nil {
 						return nil, err
@@ -114,19 +115,20 @@ func TestDiscoverer_Discover(t *testing.T) {
 				return []any{oldaddressProviderRetriever}
 			},
 			teardown: func(params []any) {
-				addressProviderRetriever = params[0].(func(deviceNames []string) ([]addressProvider, error))
+				addressProviderRetriever = params[0].(func(log zerolog.Logger, deviceNames []string) ([]addressProvider, error))
 			},
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			var params []any
+			if tt.setup != nil {
+				params = tt.setup(t, &tt.fields)
+			}
 			d := &Discoverer{
 				transportInstanceCreationQueue: tt.fields.transportInstanceCreationQueue,
 				deviceScanningQueue:            tt.fields.deviceScanningQueue,
-			}
-			var params []any
-			if tt.setup != nil {
-				params = tt.setup()
+				log:                            testutils.ProduceTestingLogger(t),
 			}
 			tt.wantErr(t, d.Discover(tt.args.ctx, tt.args.callback, tt.args.discoveryOptions...), fmt.Sprintf("Discover(%v, func(), %v)", tt.args.ctx, tt.args.discoveryOptions))
 			if tt.teardown != nil {
@@ -138,8 +140,8 @@ func TestDiscoverer_Discover(t *testing.T) {
 
 func TestDiscoverer_createDeviceScanDispatcher(t *testing.T) {
 	type fields struct {
-		transportInstanceCreationQueue utils.Executor
-		deviceScanningQueue            utils.Executor
+		transportInstanceCreationQueue pool.Executor
+		deviceScanningQueue            pool.Executor
 	}
 	type args struct {
 		tcpTransportInstance *tcp.TransportInstance
@@ -201,6 +203,7 @@ func TestDiscoverer_createDeviceScanDispatcher(t *testing.T) {
 			d := &Discoverer{
 				transportInstanceCreationQueue: tt.fields.transportInstanceCreationQueue,
 				deviceScanningQueue:            tt.fields.deviceScanningQueue,
+				log:                            testutils.ProduceTestingLogger(t),
 			}
 			dispatcher := d.createDeviceScanDispatcher(tt.args.tcpTransportInstance, func(event apiModel.PlcDiscoveryItem) {
 				tt.args.callback(t, event)
@@ -213,8 +216,8 @@ func TestDiscoverer_createDeviceScanDispatcher(t *testing.T) {
 
 func TestDiscoverer_createTransportInstanceDispatcher(t *testing.T) {
 	type fields struct {
-		transportInstanceCreationQueue utils.Executor
-		deviceScanningQueue            utils.Executor
+		transportInstanceCreationQueue pool.Executor
+		deviceScanningQueue            pool.Executor
 	}
 	type args struct {
 		ctx                context.Context
@@ -282,6 +285,7 @@ func TestDiscoverer_createTransportInstanceDispatcher(t *testing.T) {
 			d := &Discoverer{
 				transportInstanceCreationQueue: tt.fields.transportInstanceCreationQueue,
 				deviceScanningQueue:            tt.fields.deviceScanningQueue,
+				log:                            testutils.ProduceTestingLogger(t),
 			}
 			dispatcher := d.createTransportInstanceDispatcher(tt.args.ctx, tt.args.wg, tt.args.ip, tt.args.tcpTransport, tt.args.transportInstances, tt.args.cBusPort, tt.args.addressLogger)
 			assert.NotNilf(t, dispatcher, "createTransportInstanceDispatcher(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.wg, tt.args.ip, tt.args.tcpTransport, tt.args.transportInstances)
@@ -301,8 +305,8 @@ func TestDiscoverer_createTransportInstanceDispatcher(t *testing.T) {
 
 func TestDiscoverer_extractDeviceNames(t *testing.T) {
 	type fields struct {
-		transportInstanceCreationQueue utils.Executor
-		deviceScanningQueue            utils.Executor
+		transportInstanceCreationQueue pool.Executor
+		deviceScanningQueue            pool.Executor
 	}
 	type args struct {
 		discoveryOptions []options.WithDiscoveryOption
@@ -342,6 +346,7 @@ func TestDiscoverer_extractDeviceNames(t *testing.T) {
 			d := &Discoverer{
 				transportInstanceCreationQueue: tt.fields.transportInstanceCreationQueue,
 				deviceScanningQueue:            tt.fields.deviceScanningQueue,
+				log:                            testutils.ProduceTestingLogger(t),
 			}
 			assert.Equalf(t, tt.want, d.extractDeviceNames(tt.args.discoveryOptions...), "extractDeviceNames(%v)", tt.args.discoveryOptions)
 		})
diff --git a/plc4go/internal/cbus/Driver.go b/plc4go/internal/cbus/Driver.go
index f8043723c7..27e38a0739 100644
--- a/plc4go/internal/cbus/Driver.go
+++ b/plc4go/internal/cbus/Driver.go
@@ -21,70 +21,73 @@ package cbus
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
+	"github.com/rs/zerolog"
 	"net/url"
 	"strconv"
 
 	"github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
-	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type Driver struct {
 	_default.DefaultDriver
-	tm                      spi.RequestTransactionManager
+	tm                      transactions.RequestTransactionManager
 	awaitSetupComplete      bool
 	awaitDisconnectComplete bool
+
+	log zerolog.Logger
 }
 
-func NewDriver() plc4go.PlcDriver {
+func NewDriver(_options ...options.WithOption) plc4go.PlcDriver {
 	driver := &Driver{
-		tm:                      spi.NewRequestTransactionManager(1),
+		tm:                      transactions.NewRequestTransactionManager(1, _options...),
 		awaitSetupComplete:      true,
 		awaitDisconnectComplete: true,
+		log:                     options.ExtractCustomLogger(_options...),
 	}
 	driver.DefaultDriver = _default.NewDefaultDriver(driver, "c-bus", "Clipsal Bus", "tcp", NewTagHandler())
 	return driver
 }
 
-func (m *Driver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
-	log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(options))
+func (m *Driver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, driverOptions map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	m.log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(driverOptions))
 	// Get the transport specified in the url
 	transport, ok := transports[transportUrl.Scheme]
 	if !ok {
-		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
+		m.log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
 		return m.reportError(errors.Errorf("couldn't find transport for given transport url %v", transportUrl))
 	}
 	// Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
-	options["defaultTcpPort"] = []string{strconv.FormatUint(uint64(readWriteModel.CBusConstants_CBUSTCPDEFAULTPORT), 10)}
+	driverOptions["defaultTcpPort"] = []string{strconv.FormatUint(uint64(readWriteModel.CBusConstants_CBUSTCPDEFAULTPORT), 10)}
 	// Have the transport create a new transport-instance.
-	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+	transportInstance, err := transport.CreateTransportInstance(transportUrl, driverOptions)
 	if err != nil {
-		log.Error().Err(err).Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", options["defaultTcpPort"])
+		m.log.Error().Err(err).Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", driverOptions["defaultTcpPort"])
 		return m.reportError(errors.Wrapf(err, "couldn't initialize transport configuration for given transport url %s", transportUrl.String()))
 	}
 
-	configuration, err := ParseFromOptions(options)
+	configuration, err := ParseFromOptions(m.log, driverOptions)
 	if err != nil {
-		log.Error().Err(err).Msgf("Invalid options")
+		m.log.Error().Err(err).Msgf("Invalid options")
 		return m.reportError(errors.Wrap(err, "Invalid options"))
 	}
 
-	codec := NewMessageCodec(transportInstance)
-	log.Debug().Msgf("working with codec %#v", codec)
+	codec := NewMessageCodec(transportInstance, options.WithCustomLogger(m.log))
+	m.log.Debug().Msgf("working with codec %#v", codec)
 
 	driverContext := NewDriverContext(configuration)
 	driverContext.awaitSetupComplete = m.awaitSetupComplete
 	driverContext.awaitDisconnectComplete = m.awaitDisconnectComplete
 
 	// Create the new connection
-	connection := NewConnection(codec, configuration, driverContext, m.GetPlcTagHandler(), m.tm, options)
-	log.Debug().Msg("created connection, connecting now")
+	connection := NewConnection(codec, configuration, driverContext, m.GetPlcTagHandler(), m.tm, driverOptions, options.WithCustomLogger(m.log))
+	m.log.Debug().Msg("created connection, connecting now")
 	return connection.ConnectWithContext(ctx)
 }
 
@@ -107,5 +110,5 @@ func (m *Driver) SupportsDiscovery() bool {
 }
 
 func (m *Driver) DiscoverWithContext(ctx context.Context, callback func(event apiModel.PlcDiscoveryItem), discoveryOptions ...options.WithDiscoveryOption) error {
-	return NewDiscoverer().Discover(ctx, callback, discoveryOptions...)
+	return NewDiscoverer(options.WithCustomLogger(m.log)).Discover(ctx, callback, discoveryOptions...)
 }
diff --git a/plc4go/internal/cbus/Driver_test.go b/plc4go/internal/cbus/Driver_test.go
index 0c2ad3b676..7b75e79cc2 100644
--- a/plc4go/internal/cbus/Driver_test.go
+++ b/plc4go/internal/cbus/Driver_test.go
@@ -24,9 +24,9 @@ import (
 	"fmt"
 	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/transports/test"
 	"github.com/apache/plc4x/plc4go/spi/utils"
@@ -40,7 +40,7 @@ import (
 func TestDriver_DiscoverWithContext(t *testing.T) {
 	type fields struct {
 		DefaultDriver           _default.DefaultDriver
-		tm                      spi.RequestTransactionManager
+		tm                      transactions.RequestTransactionManager
 		awaitSetupComplete      bool
 		awaitDisconnectComplete bool
 	}
@@ -83,7 +83,7 @@ func TestDriver_DiscoverWithContext(t *testing.T) {
 func TestDriver_GetConnectionWithContext(t *testing.T) {
 	type fields struct {
 		DefaultDriver           _default.DefaultDriver
-		tm                      spi.RequestTransactionManager
+		tm                      transactions.RequestTransactionManager
 		awaitSetupComplete      bool
 		awaitDisconnectComplete bool
 	}
@@ -273,7 +273,7 @@ func TestNewDriver(t *testing.T) {
 func TestDriver_reportError(t *testing.T) {
 	type fields struct {
 		DefaultDriver           _default.DefaultDriver
-		tm                      spi.RequestTransactionManager
+		tm                      transactions.RequestTransactionManager
 		awaitSetupComplete      bool
 		awaitDisconnectComplete bool
 	}
diff --git a/plc4go/internal/cbus/MessageCodec.go b/plc4go/internal/cbus/MessageCodec.go
index 3f10f43a0b..2160eee221 100644
--- a/plc4go/internal/cbus/MessageCodec.go
+++ b/plc4go/internal/cbus/MessageCodec.go
@@ -21,6 +21,8 @@ package cbus
 
 import (
 	"bufio"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/rs/zerolog"
 	"hash/crc32"
 
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
@@ -28,7 +30,6 @@ import (
 	"github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type MessageCodec struct {
@@ -43,16 +44,19 @@ type MessageCodec struct {
 	hashEncountered uint
 
 	currentlyReportedServerErrors uint
+
+	log zerolog.Logger
 }
 
-func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+func NewMessageCodec(transportInstance transports.TransportInstance, _options ...options.WithOption) *MessageCodec {
 	codec := &MessageCodec{
 		requestContext: readWriteModel.NewRequestContext(false),
 		cbusOptions:    readWriteModel.NewCBusOptions(false, false, false, false, false, false, false, false, false),
 		monitoredMMIs:  make(chan readWriteModel.CALReply, 100),
 		monitoredSALs:  make(chan readWriteModel.MonitoredSAL, 100),
+		log:            options.ExtractCustomLogger(_options...),
 	}
-	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance, _default.WithCustomMessageHandler(extractMMIAndSAL))
+	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance, append(_options, _default.WithCustomMessageHandler(extractMMIAndSAL))...)
 	return codec
 }
 
@@ -61,7 +65,7 @@ func (m *MessageCodec) GetCodec() spi.MessageCodec {
 }
 
 func (m *MessageCodec) Send(message spi.Message) error {
-	log.Trace().Msg("Sending message")
+	m.log.Trace().Msg("Sending message")
 	// Cast the message to the correct type of struct
 	cbusMessage, ok := message.(readWriteModel.CBusMessage)
 	if !ok {
@@ -70,7 +74,7 @@ func (m *MessageCodec) Send(message spi.Message) error {
 
 	// Set the right request context
 	m.requestContext = CreateRequestContext(cbusMessage)
-	log.Debug().Msgf("Created request context\n%s", m.requestContext)
+	m.log.Debug().Msgf("Created request context\n%s", m.requestContext)
 
 	// Serialize the request
 	theBytes, err := cbusMessage.Serialize()
@@ -87,13 +91,13 @@ func (m *MessageCodec) Send(message spi.Message) error {
 }
 
 func (m *MessageCodec) Receive() (spi.Message, error) {
-	log.Trace().Msg("Receive")
+	m.log.Trace().Msg("Receive")
 	ti := m.GetTransportInstance()
 	confirmation := false
 	// Fill the buffer
 	{
 		if err := ti.FillBuffer(func(pos uint, currentByte byte, reader *bufio.Reader) bool {
-			log.Trace().Uint8("byte", currentByte).Msg("current byte")
+			m.log.Trace().Uint8("byte", currentByte).Msg("current byte")
 			switch currentByte {
 			case
 				readWriteModel.ResponseTermination_CR,
@@ -116,26 +120,26 @@ func (m *MessageCodec) Receive() (spi.Message, error) {
 				return true
 			}
 		}); err != nil {
-			log.Debug().Err(err).Msg("Error filling buffer")
+			m.log.Debug().Err(err).Msg("Error filling buffer")
 		}
 	}
-	log.Trace().Msg("Buffer filled")
+	m.log.Trace().Msg("Buffer filled")
 
 	// Check how many readable bytes we have
 	var readableBytes uint32
 	{
 		numBytesAvailableInBuffer, err := ti.GetNumBytesAvailableInBuffer()
 		if err != nil {
-			log.Warn().Err(err).Msg("Got error reading")
+			m.log.Warn().Err(err).Msg("Got error reading")
 			return nil, nil
 		}
 		if numBytesAvailableInBuffer == 0 {
-			log.Trace().Msg("Nothing to read")
+			m.log.Trace().Msg("Nothing to read")
 			return nil, nil
 		}
 		readableBytes = numBytesAvailableInBuffer
 	}
-	log.Trace().Msgf("%d bytes available in buffer", readableBytes)
+	m.log.Trace().Msgf("%d bytes available in buffer", readableBytes)
 
 	// Check for an isolated error
 	if bytes, err := ti.PeekReadableBytes(1); err == nil && (bytes[0] == byte(readWriteModel.ConfirmationType_CHECKSUM_FAILURE)) {
@@ -175,20 +179,20 @@ lookingForTheEnd:
 			break lookingForTheEnd
 		}
 	}
-	log.Trace().Msgf("indexOfCR %d,indexOfLF %d,indexOfConfirmation %d", indexOfCR, indexOfLF, indexOfConfirmation)
+	m.log.Trace().Msgf("indexOfCR %d,indexOfLF %d,indexOfConfirmation %d", indexOfCR, indexOfLF, indexOfConfirmation)
 	if indexOfCR < 0 && indexOfLF >= 0 {
 		// This means that the package is garbage as a lf is always prefixed with a cr
-		log.Debug().Err(err).Msg("Error reading")
+		m.log.Debug().Err(err).Msg("Error reading")
 		garbage, err := ti.Read(readableBytes)
-		log.Warn().Bytes("garbage", garbage).Msg("Garbage bytes")
+		m.log.Warn().Bytes("garbage", garbage).Msg("Garbage bytes")
 		return nil, err
 	}
 	if indexOfCR+1 == indexOfLF {
-		log.Trace().Msg("pci response for sure")
+		m.log.Trace().Msg("pci response for sure")
 		// This means a <cr> is directly followed by a <lf> which means that we know for sure this is a response
 		pciResponse = true
 	} else if indexOfCR >= 0 && int(readableBytes) >= indexOfCR+2 && peekedBytes[+indexOfCR+1] != '\n' {
-		log.Trace().Msg("pci request for sure")
+		m.log.Trace().Msg("pci request for sure")
 		// We got a request to pci for sure because the cr is followed by something else than \n
 		requestToPci = true
 	}
@@ -202,24 +206,24 @@ lookingForTheEnd:
 		if newPackageHash == m.lastPackageHash {
 			m.hashEncountered++
 		}
-		log.Trace().Msgf("new hash %x, last hash %x, seen %d times", newPackageHash, m.lastPackageHash, m.hashEncountered)
+		m.log.Trace().Msgf("new hash %x, last hash %x, seen %d times", newPackageHash, m.lastPackageHash, m.hashEncountered)
 		m.lastPackageHash = newPackageHash
 		if m.hashEncountered < numberOfCyclesToWait {
-			log.Trace().Msg("Waiting for more data")
+			m.log.Trace().Msg("Waiting for more data")
 			return nil, nil
 		} else {
-			log.Trace().Msgf("stopping after ~%dms", estimatedElapsedTime)
+			m.log.Trace().Msgf("stopping after ~%dms", estimatedElapsedTime)
 			// after numberOfCyclesToWait*10 ms we give up finding a lf
 			m.lastPackageHash, m.hashEncountered = 0, 0
 			if indexOfCR >= 0 {
-				log.Trace().Msg("setting requestToPci")
+				m.log.Trace().Msg("setting requestToPci")
 				requestToPci = true
 			}
 		}
 	}
 	if !pciResponse && !requestToPci && !confirmation {
 		// Apparently we have not found any message yet
-		log.Trace().Msg("no message found yet")
+		m.log.Trace().Msg("no message found yet")
 		return nil, nil
 	}
 
@@ -255,20 +259,20 @@ lookingForTheEnd:
 		}
 		// Now we report the errors one by one so for every request we get a proper rejection
 		if foundErrors > m.currentlyReportedServerErrors {
-			log.Debug().Msgf("We found %d errors in the current message. We have %d reported already", foundErrors, m.currentlyReportedServerErrors)
+			m.log.Debug().Msgf("We found %d errors in the current message. We have %d reported already", foundErrors, m.currentlyReportedServerErrors)
 			m.currentlyReportedServerErrors++
 			return readWriteModel.CBusMessageParse([]byte{'!'}, true, m.requestContext, m.cbusOptions)
 		}
 		if foundErrors > 0 {
-			log.Debug().Msgf("We should have reported all errors by now (%d in total which we reported %d), so we resetting the count", foundErrors, m.currentlyReportedServerErrors)
+			m.log.Debug().Msgf("We should have reported all errors by now (%d in total which we reported %d), so we resetting the count", foundErrors, m.currentlyReportedServerErrors)
 			m.currentlyReportedServerErrors = 0
 		}
-		log.Trace().Msgf("currentlyReportedServerErrors %d should be 0", m.currentlyReportedServerErrors)
+		m.log.Trace().Msgf("currentlyReportedServerErrors %d should be 0", m.currentlyReportedServerErrors)
 	}
 
 	var rawInput []byte
 	{
-		log.Trace().Msgf("Read packet length %d", packetLength)
+		m.log.Trace().Msgf("Read packet length %d", packetLength)
 		read, err := ti.Read(uint32(packetLength))
 		if err != nil {
 			return nil, errors.Wrap(err, "Invalid state... If we have peeked that before we should be able to read that now")
@@ -284,17 +288,17 @@ lookingForTheEnd:
 			}
 		}
 	}
-	log.Debug().Msgf("Parsing %q", sanitizedInput)
+	m.log.Debug().Msgf("Parsing %q", sanitizedInput)
 	cBusMessage, err := readWriteModel.CBusMessageParse(sanitizedInput, pciResponse, m.requestContext, m.cbusOptions)
 	if err != nil {
-		log.Debug().Err(err).Msg("First Parse Failed")
+		m.log.Debug().Err(err).Msg("First Parse Failed")
 		{ // Try SAL
 			requestContext := readWriteModel.NewRequestContext(false)
 			cBusMessage, secondErr := readWriteModel.CBusMessageParse(sanitizedInput, pciResponse, requestContext, m.cbusOptions)
 			if secondErr == nil {
 				return cBusMessage, nil
 			} else {
-				log.Debug().Err(secondErr).Msg("SAL parse failed too")
+				m.log.Debug().Err(secondErr).Msg("SAL parse failed too")
 			}
 		}
 		{ // Try MMI
@@ -304,11 +308,11 @@ lookingForTheEnd:
 			if secondErr == nil {
 				return cBusMessage, nil
 			} else {
-				log.Debug().Err(secondErr).Msg("CAL parse failed too")
+				m.log.Debug().Err(secondErr).Msg("CAL parse failed too")
 			}
 		}
 
-		log.Warn().Err(err).Msg("error parsing")
+		m.log.Warn().Err(err).Msg("error parsing")
 		return nil, nil
 	}
 	return cBusMessage, nil
diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go
index 645595bbdf..0b3cedc4ff 100644
--- a/plc4go/internal/cbus/Reader.go
+++ b/plc4go/internal/cbus/Reader.go
@@ -21,6 +21,9 @@ package cbus
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
+	"github.com/rs/zerolog"
 	"sync"
 	"time"
 
@@ -30,25 +33,28 @@ import (
 	"github.com/apache/plc4x/plc4go/spi"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type Reader struct {
 	alphaGenerator *AlphaGenerator
 	messageCodec   *MessageCodec
-	tm             spi.RequestTransactionManager
+	tm             transactions.RequestTransactionManager
+
+	log zerolog.Logger
 }
 
-func NewReader(tpduGenerator *AlphaGenerator, messageCodec *MessageCodec, tm spi.RequestTransactionManager) *Reader {
+func NewReader(tpduGenerator *AlphaGenerator, messageCodec *MessageCodec, tm transactions.RequestTransactionManager, _options ...options.WithOption) *Reader {
 	return &Reader{
 		alphaGenerator: tpduGenerator,
 		messageCodec:   messageCodec,
 		tm:             tm,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
 func (m *Reader) Read(ctx context.Context, readRequest apiModel.PlcReadRequest) <-chan apiModel.PlcReadRequestResult {
-	log.Trace().Msg("Reading")
+	m.log.Trace().Msg("Reading")
 	result := make(chan apiModel.PlcReadRequestResult, 1)
 	go m.readSync(ctx, readRequest, result)
 	return result
@@ -118,17 +124,17 @@ func (m *Reader) readSync(ctx context.Context, readRequest apiModel.PlcReadReque
 func (m *Reader) createMessageTransactionAndWait(ctx context.Context, messageToSend readWriteModel.CBusMessage, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), tagName string, addPlcValue func(name string, plcValue apiValues.PlcValue)) {
 	// Start a new request-transaction (Is ended in the response-handler)
 	transaction := m.tm.StartTransaction()
-	transaction.Submit(func(transaction spi.RequestTransaction) {
+	transaction.Submit(func(transaction transactions.RequestTransaction) {
 		m.sendMessageOverTheWire(ctx, transaction, messageToSend, addResponseCode, tagName, addPlcValue)
 	})
 	if err := transaction.AwaitCompletion(ctx); err != nil {
-		log.Warn().Err(err).Msg("Error while awaiting completion")
+		m.log.Warn().Err(err).Msg("Error while awaiting completion")
 	}
 }
 
-func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction spi.RequestTransaction, messageToSend readWriteModel.CBusMessage, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), tagName string, addPlcValue func(name string, plcValue apiValues.PlcValue)) {
+func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction transactions.RequestTransaction, messageToSend readWriteModel.CBusMessage, addResponseCode func(name string, responseCode apiModel.PlcResponseCode), tagName string, addPlcValue func(name string, plcValue apiValues.PlcValue)) {
 	// Send the  over the wire
-	log.Trace().Msg("Send ")
+	m.log.Trace().Msg("Send ")
 	if err := m.messageCodec.SendRequest(ctx, messageToSend, func(cbusMessage spi.Message) bool {
 		messageToClient, ok := cbusMessage.(readWriteModel.CBusMessageToClientExactly)
 		if !ok {
@@ -149,15 +155,15 @@ func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction spi.Req
 		expectedAlpha := messageToSend.(readWriteModel.CBusMessageToServer).GetRequest().(interface{ GetAlpha() readWriteModel.Alpha }).GetAlpha().GetCharacter()
 		return actualAlpha == expectedAlpha
 	}, func(receivedMessage spi.Message) error {
-		defer func(transaction spi.RequestTransaction) {
+		defer func(transaction transactions.RequestTransaction) {
 			// This is just to make sure we don't forget to close the transaction here
 			_ = transaction.EndRequest()
 		}(transaction)
 		// Convert the response into an
-		log.Trace().Msg("convert response to ")
+		m.log.Trace().Msg("convert response to ")
 		messageToClient := receivedMessage.(readWriteModel.CBusMessageToClient)
 		if _, ok := messageToClient.GetReply().(readWriteModel.ServerErrorReplyExactly); ok {
-			log.Trace().Msg("We got a server failure")
+			m.log.Trace().Msg("We got a server failure")
 			addResponseCode(tagName, apiModel.PlcResponseCode_INVALID_DATA)
 			return transaction.EndRequest()
 		}
@@ -176,7 +182,7 @@ func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction spi.Req
 			default:
 				return transaction.FailRequest(errors.Errorf("Every code should be mapped here: %v", replyOrConfirmationConfirmation.GetConfirmation().GetConfirmationType()))
 			}
-			log.Trace().Msgf("Was no success %s:%v", tagName, responseCode)
+			m.log.Trace().Msgf("Was no success %s:%v", tagName, responseCode)
 			addResponseCode(tagName, responseCode)
 			return transaction.EndRequest()
 		}
@@ -185,15 +191,15 @@ func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction spi.Req
 		// TODO: it could be double confirmed but this is not implemented yet
 		embeddedReply, ok := replyOrConfirmationConfirmation.GetEmbeddedReply().(readWriteModel.ReplyOrConfirmationReplyExactly)
 		if !ok {
-			log.Trace().Msgf("Is a confirm only, no data. Alpha: %c", alpha.GetCharacter())
+			m.log.Trace().Msgf("Is a confirm only, no data. Alpha: %c", alpha.GetCharacter())
 			addResponseCode(tagName, apiModel.PlcResponseCode_NOT_FOUND)
 			return transaction.EndRequest()
 		}
 
-		log.Trace().Msg("Handling confirmed data")
+		m.log.Trace().Msg("Handling confirmed data")
 		// TODO: check if we can use a plcValueSerializer
 		encodedReply := embeddedReply.GetReply().(readWriteModel.ReplyEncodedReply).GetEncodedReply()
-		if err := MapEncodedReply(transaction, encodedReply, tagName, addResponseCode, addPlcValue); err != nil {
+		if err := MapEncodedReply(m.log, transaction, encodedReply, tagName, addResponseCode, addPlcValue); err != nil {
 			return errors.Wrap(err, "error encoding reply")
 		}
 		return transaction.EndRequest()
@@ -201,10 +207,10 @@ func (m *Reader) sendMessageOverTheWire(ctx context.Context, transaction spi.Req
 		addResponseCode(tagName, apiModel.PlcResponseCode_REQUEST_TIMEOUT)
 		return transaction.FailRequest(err)
 	}, time.Second*1); err != nil {
-		log.Debug().Err(err).Msgf("Error sending message for tag %s", tagName)
+		m.log.Debug().Err(err).Msgf("Error sending message for tag %s", tagName)
 		addResponseCode(tagName, apiModel.PlcResponseCode_INTERNAL_ERROR)
 		if err := transaction.FailRequest(errors.Errorf("timeout after %s", time.Second*1)); err != nil {
-			log.Debug().Err(err).Msg("Error failing request")
+			m.log.Debug().Err(err).Msg("Error failing request")
 		}
 	}
 }
diff --git a/plc4go/internal/cbus/Reader_test.go b/plc4go/internal/cbus/Reader_test.go
index 54050ce9f3..1ead699a20 100644
--- a/plc4go/internal/cbus/Reader_test.go
+++ b/plc4go/internal/cbus/Reader_test.go
@@ -24,8 +24,10 @@ import (
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
-	"github.com/apache/plc4x/plc4go/spi"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/transports/test"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
@@ -42,7 +44,7 @@ func TestNewReader(t *testing.T) {
 	type args struct {
 		tpduGenerator *AlphaGenerator
 		messageCodec  *MessageCodec
-		tm            spi.RequestTransactionManager
+		tm            transactions.RequestTransactionManager
 	}
 	tests := []struct {
 		name string
@@ -60,7 +62,10 @@ func TestNewReader(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			assert.Equalf(t, tt.want, NewReader(tt.args.tpduGenerator, tt.args.messageCodec, tt.args.tm), "NewReader(%v, %v, %v)", tt.args.tpduGenerator, tt.args.messageCodec, tt.args.tm)
+			logger := testutils.ProduceTestingLogger(t)
+			reader := NewReader(tt.args.tpduGenerator, tt.args.messageCodec, tt.args.tm, options.WithCustomLogger(logger))
+			tt.want.log = logger
+			assert.Equalf(t, tt.want, reader, "NewReader(%v, %v, %v)", tt.args.tpduGenerator, tt.args.messageCodec, tt.args.tm)
 		})
 	}
 }
@@ -69,7 +74,7 @@ func TestReader_Read(t *testing.T) {
 	type fields struct {
 		alphaGenerator *AlphaGenerator
 		messageCodec   *MessageCodec
-		tm             spi.RequestTransactionManager
+		tm             transactions.RequestTransactionManager
 	}
 	type args struct {
 		ctx         context.Context
@@ -118,7 +123,7 @@ func TestReader_readSync(t *testing.T) {
 	type fields struct {
 		alphaGenerator *AlphaGenerator
 		messageCodec   *MessageCodec
-		tm             spi.RequestTransactionManager
+		tm             transactions.RequestTransactionManager
 	}
 	type args struct {
 		ctx         context.Context
@@ -129,6 +134,7 @@ func TestReader_readSync(t *testing.T) {
 		name            string
 		fields          fields
 		args            args
+		setup           func(t *testing.T, fields *fields)
 		resultEvaluator func(t *testing.T, results chan apiModel.PlcReadRequestResult) bool
 	}{
 		{
@@ -173,7 +179,6 @@ func TestReader_readSync(t *testing.T) {
 					}
 					return codec
 				}(),
-				tm: spi.NewRequestTransactionManager(10),
 			},
 			args: args{
 				ctx: context.Background(),
@@ -189,6 +194,9 @@ func TestReader_readSync(t *testing.T) {
 				),
 				result: make(chan apiModel.PlcReadRequestResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				fields.tm = transactions.NewRequestTransactionManager(10, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+			},
 			resultEvaluator: func(t *testing.T, results chan apiModel.PlcReadRequestResult) bool {
 				timer := time.NewTimer(2 * time.Second)
 				defer timer.Stop()
@@ -265,7 +273,6 @@ func TestReader_readSync(t *testing.T) {
 					}
 					return codec
 				}(),
-				tm: spi.NewRequestTransactionManager(10),
 			},
 			args: args{
 				ctx: func() context.Context {
@@ -285,6 +292,9 @@ func TestReader_readSync(t *testing.T) {
 				),
 				result: make(chan apiModel.PlcReadRequestResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				fields.tm = transactions.NewRequestTransactionManager(10, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+			},
 			resultEvaluator: func(t *testing.T, results chan apiModel.PlcReadRequestResult) bool {
 				timer := time.NewTimer(2 * time.Second)
 				defer timer.Stop()
@@ -324,7 +334,6 @@ func TestReader_readSync(t *testing.T) {
 					}
 					return codec
 				}(),
-				tm: spi.NewRequestTransactionManager(10),
 			},
 			args: args{
 				ctx: func() context.Context {
@@ -344,6 +353,9 @@ func TestReader_readSync(t *testing.T) {
 				),
 				result: make(chan apiModel.PlcReadRequestResult, 1),
 			},
+			setup: func(t *testing.T, fields *fields) {
+				fields.tm = transactions.NewRequestTransactionManager(10, options.WithCustomLogger(testutils.ProduceTestingLogger(t)))
+			},
 			resultEvaluator: func(t *testing.T, results chan apiModel.PlcReadRequestResult) bool {
 				timer := time.NewTimer(2 * time.Second)
 				defer timer.Stop()
@@ -359,6 +371,9 @@ func TestReader_readSync(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.setup != nil {
+				tt.setup(t, &tt.fields)
+			}
 			m := &Reader{
 				alphaGenerator: tt.fields.alphaGenerator,
 				messageCodec:   tt.fields.messageCodec,
@@ -374,11 +389,11 @@ func TestReader_sendMessageOverTheWire(t *testing.T) {
 	type fields struct {
 		alphaGenerator *AlphaGenerator
 		messageCodec   *MessageCodec
-		tm             spi.RequestTransactionManager
+		tm             transactions.RequestTransactionManager
 	}
 	type args struct {
 		ctx             context.Context
-		transaction     spi.RequestTransaction
+		transaction     transactions.RequestTransaction
 		messageToSend   readWriteModel.CBusMessage
 		addResponseCode func(t *testing.T, wg *sync.WaitGroup) func(name string, responseCode apiModel.PlcResponseCode)
 		tagName         string
diff --git a/plc4go/internal/cbus/Subscriber.go b/plc4go/internal/cbus/Subscriber.go
index c9857a20d1..bc13fcd3bc 100644
--- a/plc4go/internal/cbus/Subscriber.go
+++ b/plc4go/internal/cbus/Subscriber.go
@@ -22,7 +22,9 @@ package cbus
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 	"strings"
 	"time"
 
@@ -31,18 +33,21 @@ import (
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	spiValues "github.com/apache/plc4x/plc4go/spi/values"
-	"github.com/rs/zerolog/log"
 )
 
 type Subscriber struct {
 	connection *Connection
 	consumers  map[*spiModel.DefaultPlcConsumerRegistration]apiModel.PlcSubscriptionEventConsumer
+
+	log zerolog.Logger
 }
 
-func NewSubscriber(connection *Connection) *Subscriber {
+func NewSubscriber(connection *Connection, _options ...options.WithOption) *Subscriber {
 	return &Subscriber{
 		connection: connection,
 		consumers:  make(map[*spiModel.DefaultPlcConsumerRegistration]apiModel.PlcSubscriptionEventConsumer),
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
@@ -119,7 +124,7 @@ func (m *Subscriber) handleMonitoredMMI(calReply readWriteModel.CALReply) bool {
 func (m *Subscriber) offerMMI(unitAddressString string, calData readWriteModel.CALData, subscriptionHandle *SubscriptionHandle, consumer apiModel.PlcSubscriptionEventConsumer) bool {
 	tag, ok := subscriptionHandle.tag.(*mmiMonitorTag)
 	if !ok {
-		log.Debug().Msgf("Unusable tag for mmi subscription %s", subscriptionHandle.tag)
+		m.log.Debug().Msgf("Unusable tag for mmi subscription %s", subscriptionHandle.tag)
 		return false
 	}
 
@@ -135,7 +140,7 @@ func (m *Subscriber) offerMMI(unitAddressString string, calData readWriteModel.C
 	if unitAddress := tag.GetUnitAddress(); unitAddress != nil {
 		unitSuffix := fmt.Sprintf("u%d", unitAddress.GetAddress())
 		if !strings.HasSuffix(unitAddressString, unitSuffix) {
-			log.Debug().Msgf("Current address string %s has not the suffix %s", unitAddressString, unitSuffix)
+			m.log.Debug().Msgf("Current address string %s has not the suffix %s", unitAddressString, unitSuffix)
 			return false
 		}
 	}
@@ -217,12 +222,12 @@ func (m *Subscriber) offerMMI(unitAddressString string, calData readWriteModel.C
 			plcValues[tagName] = spiValues.NewPlcList(plcListValues)
 		}
 	default:
-		log.Error().Msgf("Unmapped type %T", calData)
+		m.log.Error().Msgf("Unmapped type %T", calData)
 		return false
 	}
 	if application := tag.GetApplication(); application != nil {
 		if actualApplicationIdString := application.ApplicationId().String(); applicationString != actualApplicationIdString {
-			log.Debug().Msgf("Current application id %s  doesn't match actual id %s", unitAddressString, actualApplicationIdString)
+			m.log.Debug().Msgf("Current application id %s  doesn't match actual id %s", unitAddressString, actualApplicationIdString)
 			return false
 		}
 	}
@@ -251,7 +256,7 @@ func (m *Subscriber) handleMonitoredSAL(sal readWriteModel.MonitoredSAL) bool {
 func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandle *SubscriptionHandle, consumer apiModel.PlcSubscriptionEventConsumer) bool {
 	tag, ok := subscriptionHandle.tag.(*salMonitorTag)
 	if !ok {
-		log.Debug().Msgf("Unusable tag for mmi subscription %s", subscriptionHandle.tag)
+		m.log.Debug().Msgf("Unusable tag for mmi subscription %s", subscriptionHandle.tag)
 		return false
 	}
 	tags := map[string]apiModel.PlcTag{}
@@ -295,7 +300,7 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 	if unitAddress := tag.GetUnitAddress(); unitAddress != nil {
 		unitSuffix := fmt.Sprintf("u%d", unitAddress.GetAddress())
 		if !strings.HasSuffix(unitAddressString, unitSuffix) {
-			log.Debug().Msgf("Current address string %s has not the suffix %s", unitAddressString, unitSuffix)
+			m.log.Debug().Msgf("Current address string %s has not the suffix %s", unitAddressString, unitSuffix)
 			return false
 		}
 	}
@@ -303,7 +308,7 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 
 	if application := tag.GetApplication(); application != nil {
 		if actualApplicationIdString := application.ApplicationId().String(); applicationString != actualApplicationIdString {
-			log.Debug().Msgf("Current application id %s  doesn't match actual id %s", unitAddressString, actualApplicationIdString)
+			m.log.Debug().Msgf("Current application id %s  doesn't match actual id %s", unitAddressString, actualApplicationIdString)
 			return false
 		}
 	}
@@ -325,7 +330,7 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 	case readWriteModel.SALDataErrorReportingExactly:
 		commandTypeGetter = salData.GetErrorReportingData().GetCommandType()
 	case readWriteModel.SALDataFreeUsageExactly:
-		log.Info().Msg("Unknown command type")
+		m.log.Info().Msg("Unknown command type")
 	case readWriteModel.SALDataHeatingExactly:
 		commandTypeGetter = salData.GetHeatingData().GetCommandType()
 	case readWriteModel.SALDataHvacActuatorExactly:
@@ -343,9 +348,9 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 	case readWriteModel.SALDataPoolsSpasPondsFountainsControlExactly:
 		commandTypeGetter = salData.GetPoolsSpaPondsFountainsData().GetCommandType()
 	case readWriteModel.SALDataReservedExactly:
-		log.Info().Msg("Unknown command type")
+		m.log.Info().Msg("Unknown command type")
 	case readWriteModel.SALDataRoomControlSystemExactly:
-		log.Info().Msg("Unknown command type not implemented yet") // TODO: implement once there
+		m.log.Info().Msg("Unknown command type not implemented yet") // TODO: implement once there
 	case readWriteModel.SALDataSecurityExactly:
 		commandTypeGetter = salData.GetSecurityData().GetCommandType()
 	case readWriteModel.SALDataTelephonyStatusAndControlExactly:
@@ -353,13 +358,13 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 	case readWriteModel.SALDataTemperatureBroadcastExactly:
 		commandTypeGetter = salData.GetTemperatureBroadcastData().GetCommandType()
 	case readWriteModel.SALDataTestingExactly:
-		log.Info().Msg("Unknown command type not implemented yet") // TODO: implement once there
+		m.log.Info().Msg("Unknown command type not implemented yet") // TODO: implement once there
 	case readWriteModel.SALDataTriggerControlExactly:
 		commandTypeGetter = salData.GetTriggerControlData().GetCommandType()
 	case readWriteModel.SALDataVentilationExactly:
 		commandTypeGetter = salData.GetVentilationData().GetCommandType()
 	default:
-		log.Error().Msgf("Unmapped type %T", salData)
+		m.log.Error().Msgf("Unmapped type %T", salData)
 	}
 	commandType := "Unknown"
 	if commandTypeGetter != nil {
@@ -372,7 +377,7 @@ func (m *Subscriber) offerSAL(sal readWriteModel.MonitoredSAL, subscriptionHandl
 	rbvb := spiValues.NewWriteBufferPlcValueBased()
 	err := salData.SerializeWithWriteBuffer(context.Background(), rbvb)
 	if err != nil {
-		log.Error().Err(err).Msg("Error serializing to plc value... just returning it as string")
+		m.log.Error().Err(err).Msg("Error serializing to plc value... just returning it as string")
 		plcValues[tagName] = spiValues.NewPlcSTRING(fmt.Sprintf("%s", salData))
 	} else {
 		plcValues[tagName] = rbvb.GetPlcValue()
diff --git a/plc4go/internal/cbus/Writer.go b/plc4go/internal/cbus/Writer.go
index 2883c0787b..35b13f71dc 100644
--- a/plc4go/internal/cbus/Writer.go
+++ b/plc4go/internal/cbus/Writer.go
@@ -21,6 +21,9 @@ package cbus
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
+	"github.com/rs/zerolog"
 	"sync"
 	"time"
 
@@ -29,25 +32,28 @@ import (
 	"github.com/apache/plc4x/plc4go/spi"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 type Writer struct {
 	alphaGenerator *AlphaGenerator
 	messageCodec   *MessageCodec
-	tm             spi.RequestTransactionManager
+	tm             transactions.RequestTransactionManager
+
+	log zerolog.Logger
 }
 
-func NewWriter(tpduGenerator *AlphaGenerator, messageCodec *MessageCodec, tm spi.RequestTransactionManager) *Writer {
+func NewWriter(tpduGenerator *AlphaGenerator, messageCodec *MessageCodec, tm transactions.RequestTransactionManager, _options ...options.WithOption) *Writer {
 	return &Writer{
 		alphaGenerator: tpduGenerator,
 		messageCodec:   messageCodec,
 		tm:             tm,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
 func (m *Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteRequest) <-chan apiModel.PlcWriteRequestResult {
-	log.Trace().Msg("Writing")
+	m.log.Trace().Msg("Writing")
 	result := make(chan apiModel.PlcWriteRequestResult, 1)
 	go func() {
 		defer func() {
@@ -103,9 +109,9 @@ func (m *Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteReques
 			tagNameCopy := tagName
 			// Start a new request-transaction (Is ended in the response-handler)
 			transaction := m.tm.StartTransaction()
-			transaction.Submit(func(transaction spi.RequestTransaction) {
+			transaction.Submit(func(transaction transactions.RequestTransaction) {
 				// Send the  over the wire
-				log.Trace().Msg("Send ")
+				m.log.Trace().Msg("Send ")
 				if err := m.messageCodec.SendRequest(ctx, messageToSend, func(receivedMessage spi.Message) bool {
 					cbusMessage, ok := receivedMessage.(readWriteModel.CBusMessageExactly)
 					if !ok {
@@ -131,12 +137,12 @@ func (m *Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteReques
 					addResponseCode(tagName, apiModel.PlcResponseCode_OK)
 					return transaction.EndRequest()
 				}, func(err error) error {
-					log.Debug().Msgf("Error waiting for tag %s", tagNameCopy)
+					m.log.Debug().Msgf("Error waiting for tag %s", tagNameCopy)
 					addResponseCode(tagNameCopy, apiModel.PlcResponseCode_REQUEST_TIMEOUT)
 					// TODO: ok or not ok?
 					return transaction.EndRequest()
 				}, time.Second*1); err != nil {
-					log.Debug().Err(err).Msgf("Error sending message for tag %s", tagNameCopy)
+					m.log.Debug().Err(err).Msgf("Error sending message for tag %s", tagNameCopy)
 					addResponseCode(tagNameCopy, apiModel.PlcResponseCode_INTERNAL_ERROR)
 					_ = transaction.EndRequest()
 				}
diff --git a/plc4go/internal/cbus/Writer_test.go b/plc4go/internal/cbus/Writer_test.go
index b1ba9db6cf..3af6f00013 100644
--- a/plc4go/internal/cbus/Writer_test.go
+++ b/plc4go/internal/cbus/Writer_test.go
@@ -22,6 +22,7 @@ package cbus
 import (
 	"context"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	"github.com/stretchr/testify/assert"
 	"strings"
@@ -29,14 +30,13 @@ import (
 	"time"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/spi"
 )
 
 func TestNewWriter(t *testing.T) {
 	type args struct {
 		tpduGenerator *AlphaGenerator
 		messageCodec  *MessageCodec
-		tm            spi.RequestTransactionManager
+		tm            transactions.RequestTransactionManager
 	}
 	tests := []struct {
 		name string
@@ -62,7 +62,7 @@ func TestWriter_Write(t *testing.T) {
 	type fields struct {
 		alphaGenerator *AlphaGenerator
 		messageCodec   *MessageCodec
-		tm             spi.RequestTransactionManager
+		tm             transactions.RequestTransactionManager
 	}
 	type args struct {
 		ctx          context.Context
diff --git a/plc4go/internal/cbus/mock_RequestTransaction_test.go b/plc4go/internal/cbus/mock_RequestTransaction_test.go
index 119b237012..ae6861665b 100644
--- a/plc4go/internal/cbus/mock_RequestTransaction_test.go
+++ b/plc4go/internal/cbus/mock_RequestTransaction_test.go
@@ -24,7 +24,7 @@ package cbus
 import (
 	context "context"
 
-	spi "github.com/apache/plc4x/plc4go/spi"
+	transactions "github.com/apache/plc4x/plc4go/spi/transactions"
 	mock "github.com/stretchr/testify/mock"
 )
 
@@ -208,7 +208,7 @@ func (_c *MockRequestTransaction_String_Call) RunAndReturn(run func() string) *M
 }
 
 // Submit provides a mock function with given fields: operation
-func (_m *MockRequestTransaction) Submit(operation spi.RequestTransactionRunnable) {
+func (_m *MockRequestTransaction) Submit(operation transactions.RequestTransactionRunnable) {
 	_m.Called(operation)
 }
 
@@ -218,14 +218,14 @@ type MockRequestTransaction_Submit_Call struct {
 }
 
 // Submit is a helper method to define mock.On call
-//   - operation spi.RequestTransactionRunnable
+//   - operation transactions.RequestTransactionRunnable
 func (_e *MockRequestTransaction_Expecter) Submit(operation interface{}) *MockRequestTransaction_Submit_Call {
 	return &MockRequestTransaction_Submit_Call{Call: _e.mock.On("Submit", operation)}
 }
 
-func (_c *MockRequestTransaction_Submit_Call) Run(run func(operation spi.RequestTransactionRunnable)) *MockRequestTransaction_Submit_Call {
+func (_c *MockRequestTransaction_Submit_Call) Run(run func(operation transactions.RequestTransactionRunnable)) *MockRequestTransaction_Submit_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(spi.RequestTransactionRunnable))
+		run(args[0].(transactions.RequestTransactionRunnable))
 	})
 	return _c
 }
@@ -235,7 +235,7 @@ func (_c *MockRequestTransaction_Submit_Call) Return() *MockRequestTransaction_S
 	return _c
 }
 
-func (_c *MockRequestTransaction_Submit_Call) RunAndReturn(run func(spi.RequestTransactionRunnable)) *MockRequestTransaction_Submit_Call {
+func (_c *MockRequestTransaction_Submit_Call) RunAndReturn(run func(transactions.RequestTransactionRunnable)) *MockRequestTransaction_Submit_Call {
 	_c.Call.Return(run)
 	return _c
 }
diff --git a/plc4go/internal/cbus/mock_requirements.go b/plc4go/internal/cbus/mock_requirements.go
index 69bb4c4e7c..a8d06b79af 100644
--- a/plc4go/internal/cbus/mock_requirements.go
+++ b/plc4go/internal/cbus/mock_requirements.go
@@ -19,11 +19,13 @@
 
 package cbus
 
-import "github.com/apache/plc4x/plc4go/spi"
+import (
+	"github.com/apache/plc4x/plc4go/spi/transactions"
+)
 
 // Note this file is a Helper for mockery to generate use mocks from other package
 
 // Deprecated: don't use it in productive code
 type RequestTransaction interface {
-	spi.RequestTransaction
+	transactions.RequestTransaction
 }
diff --git a/plc4go/internal/cbus/mock_requirements.go b/plc4go/internal/cbus/noGlobalLog_test.go
similarity index 77%
copy from plc4go/internal/cbus/mock_requirements.go
copy to plc4go/internal/cbus/noGlobalLog_test.go
index 69bb4c4e7c..7a3475947d 100644
--- a/plc4go/internal/cbus/mock_requirements.go
+++ b/plc4go/internal/cbus/noGlobalLog_test.go
@@ -19,11 +19,7 @@
 
 package cbus
 
-import "github.com/apache/plc4x/plc4go/spi"
-
-// Note this file is a Helper for mockery to generate use mocks from other package
-
-// Deprecated: don't use it in productive code
-type RequestTransaction interface {
-	spi.RequestTransaction
+// This ensures that we don't global log
+func init() {
+	//testutils.ExplodingGlobalLogger(true)
 }
diff --git a/plc4go/internal/eip/Connection.go b/plc4go/internal/eip/Connection.go
index 54fbb595b6..2524e333db 100644
--- a/plc4go/internal/eip/Connection.go
+++ b/plc4go/internal/eip/Connection.go
@@ -22,6 +22,7 @@ package eip
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 
 	"github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
@@ -45,7 +46,7 @@ type Connection struct {
 	messageCodec              spi.MessageCodec
 	configuration             Configuration
 	driverContext             DriverContext
-	tm                        spi.RequestTransactionManager
+	tm                        transactions.RequestTransactionManager
 	sessionHandle             uint32
 	senderContext             []uint8
 	connectionId              uint32
@@ -58,7 +59,7 @@ type Connection struct {
 	tracer                    *spi.Tracer
 }
 
-func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm spi.RequestTransactionManager, options map[string][]string) *Connection {
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm transactions.RequestTransactionManager, options map[string][]string) *Connection {
 	connection := &Connection{
 		messageCodec:  messageCodec,
 		configuration: configuration,
diff --git a/plc4go/internal/eip/EipDriver.go b/plc4go/internal/eip/EipDriver.go
index 9920bdd10c..e36e27904c 100644
--- a/plc4go/internal/eip/EipDriver.go
+++ b/plc4go/internal/eip/EipDriver.go
@@ -21,10 +21,10 @@ package eip
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"net/url"
 
 	"github.com/apache/plc4x/plc4go/pkg/api"
-	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/pkg/errors"
@@ -33,14 +33,14 @@ import (
 
 type Driver struct {
 	_default.DefaultDriver
-	tm                      spi.RequestTransactionManager
+	tm                      transactions.RequestTransactionManager
 	awaitSetupComplete      bool
 	awaitDisconnectComplete bool
 }
 
 func NewDriver() plc4go.PlcDriver {
 	driver := &Driver{
-		tm:                      spi.NewRequestTransactionManager(1),
+		tm:                      transactions.NewRequestTransactionManager(1),
 		awaitSetupComplete:      true,
 		awaitDisconnectComplete: true,
 	}
diff --git a/plc4go/internal/eip/Reader.go b/plc4go/internal/eip/Reader.go
index 67dee5b772..5105835298 100644
--- a/plc4go/internal/eip/Reader.go
+++ b/plc4go/internal/eip/Reader.go
@@ -23,6 +23,7 @@ import (
 	"context"
 	"encoding/binary"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"regexp"
 	"strconv"
 	"time"
@@ -41,12 +42,12 @@ import (
 
 type Reader struct {
 	messageCodec  spi.MessageCodec
-	tm            spi.RequestTransactionManager
+	tm            transactions.RequestTransactionManager
 	configuration Configuration
 	sessionHandle *uint32
 }
 
-func NewReader(messageCodec spi.MessageCodec, tm spi.RequestTransactionManager, configuration Configuration, sessionHandle *uint32) *Reader {
+func NewReader(messageCodec spi.MessageCodec, tm transactions.RequestTransactionManager, configuration Configuration, sessionHandle *uint32) *Reader {
 	return &Reader{
 		messageCodec:  messageCodec,
 		tm:            tm,
@@ -88,7 +89,7 @@ func (m *Reader) Read(ctx context.Context, readRequest apiModel.PlcReadRequest)
 			}
 			request := readWriteModel.NewCipRRData(0, 0, typeIds, *m.sessionHandle, uint32(readWriteModel.CIPStatus_Success), []byte(DefaultSenderContext), 0)
 			transaction := m.tm.StartTransaction()
-			transaction.Submit(func(transaction spi.RequestTransaction) {
+			transaction.Submit(func(transaction transactions.RequestTransaction) {
 				if err := m.messageCodec.SendRequest(ctx, request,
 					func(message spi.Message) bool {
 						eipPacket := message.(readWriteModel.EipPacket)
diff --git a/plc4go/internal/eip/Writer.go b/plc4go/internal/eip/Writer.go
index 81f05206c5..195f753e2a 100644
--- a/plc4go/internal/eip/Writer.go
+++ b/plc4go/internal/eip/Writer.go
@@ -22,6 +22,7 @@ package eip
 import (
 	"context"
 	"encoding/binary"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"strings"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
@@ -37,13 +38,13 @@ import (
 
 type Writer struct {
 	messageCodec  spi.MessageCodec
-	tm            spi.RequestTransactionManager
+	tm            transactions.RequestTransactionManager
 	configuration Configuration
 	sessionHandle *uint32
 	senderContext *[]uint8
 }
 
-func NewWriter(messageCodec spi.MessageCodec, tm spi.RequestTransactionManager, configuration Configuration, sessionHandle *uint32, senderContext *[]uint8) Writer {
+func NewWriter(messageCodec spi.MessageCodec, tm transactions.RequestTransactionManager, configuration Configuration, sessionHandle *uint32, senderContext *[]uint8) Writer {
 	return Writer{
 		messageCodec:  messageCodec,
 		tm:            tm,
@@ -118,7 +119,7 @@ func (m Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteRequest
 					)
 					// Start a new request-transaction (Is ended in the response-handler)
 					transaction := m.tm.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
+					transaction.Submit(func(transaction transactions.RequestTransaction) {
 						// Send the  over the wire
 						if err := m.messageCodec.SendRequest(ctx, pkt, func(message spi.Message) bool {
 							eipPacket := message.(readWriteModel.EipPacket)
@@ -206,7 +207,7 @@ func (m Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteRequest
 					)
 					// Start a new request-transaction (Is ended in the response-handler)
 					transaction := m.tm.StartTransaction()
-					transaction.Submit(func(transaction spi.RequestTransaction) {
+					transaction.Submit(func(transaction transactions.RequestTransaction) {
 						// Send the  over the wire
 						if err := m.messageCodec.SendRequest(ctx, pkt, func(message spi.Message) bool {
 							eipPacket := message.(readWriteModel.EipPacket)
diff --git a/plc4go/internal/knxnetip/Discoverer.go b/plc4go/internal/knxnetip/Discoverer.go
index dd1b8ad024..45857edbe0 100644
--- a/plc4go/internal/knxnetip/Discoverer.go
+++ b/plc4go/internal/knxnetip/Discoverer.go
@@ -23,7 +23,7 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"github.com/apache/plc4x/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/spi/pool"
 	"github.com/rs/zerolog/log"
 	"net"
 	"net/url"
@@ -41,16 +41,16 @@ import (
 
 type Discoverer struct {
 	transportInstanceCreationWorkItemId atomic.Int32
-	transportInstanceCreationQueue      utils.Executor
+	transportInstanceCreationQueue      pool.Executor
 	deviceScanningWorkItemId            atomic.Int32
-	deviceScanningQueue                 utils.Executor
+	deviceScanningQueue                 pool.Executor
 }
 
 func NewDiscoverer() *Discoverer {
 	return &Discoverer{
 		// TODO: maybe a dynamic executor would be better to not waste cycles when not in use
-		transportInstanceCreationQueue: utils.NewFixedSizeExecutor(50, 100),
-		deviceScanningQueue:            utils.NewFixedSizeExecutor(50, 100),
+		transportInstanceCreationQueue: pool.NewFixedSizeExecutor(50, 100),
+		deviceScanningQueue:            pool.NewFixedSizeExecutor(50, 100),
 	}
 }
 
@@ -149,7 +149,7 @@ func (d *Discoverer) Discover(ctx context.Context, callback func(event apiModel.
 	return nil
 }
 
-func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *sync.WaitGroup, connectionUrl *url.URL, ipv4Addr net.IP, udpTransport *udp.Transport, transportInstances chan transports.TransportInstance) utils.Runnable {
+func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *sync.WaitGroup, connectionUrl *url.URL, ipv4Addr net.IP, udpTransport *udp.Transport, transportInstances chan transports.TransportInstance) pool.Runnable {
 	wg.Add(1)
 	return func() {
 		defer wg.Done()
@@ -171,7 +171,7 @@ func (d *Discoverer) createTransportInstanceDispatcher(ctx context.Context, wg *
 	}
 }
 
-func (d *Discoverer) createDeviceScanDispatcher(udpTransportInstance *udp.TransportInstance, callback func(event apiModel.PlcDiscoveryItem)) utils.Runnable {
+func (d *Discoverer) createDeviceScanDispatcher(udpTransportInstance *udp.TransportInstance, callback func(event apiModel.PlcDiscoveryItem)) pool.Runnable {
 	return func() {
 		log.Debug().Msgf("Scanning %v", udpTransportInstance)
 		// Create a codec for sending and receiving messages.
diff --git a/plc4go/internal/s7/Connection.go b/plc4go/internal/s7/Connection.go
index cc45c9111e..131bc31db2 100644
--- a/plc4go/internal/s7/Connection.go
+++ b/plc4go/internal/s7/Connection.go
@@ -22,6 +22,7 @@ package s7
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"reflect"
 	"strings"
 	"sync"
@@ -60,13 +61,13 @@ type Connection struct {
 	messageCodec  spi.MessageCodec
 	configuration Configuration
 	driverContext DriverContext
-	tm            spi.RequestTransactionManager
+	tm            transactions.RequestTransactionManager
 
 	connectionId string
 	tracer       *spi.Tracer
 }
 
-func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm spi.RequestTransactionManager, options map[string][]string) *Connection {
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, tagHandler spi.PlcTagHandler, tm transactions.RequestTransactionManager, options map[string][]string) *Connection {
 	connection := &Connection{
 		tpduGenerator: TpduGenerator{currentTpduId: 10},
 		messageCodec:  messageCodec,
diff --git a/plc4go/internal/s7/Driver.go b/plc4go/internal/s7/Driver.go
index 37d4e080a1..738e6c1f1f 100644
--- a/plc4go/internal/s7/Driver.go
+++ b/plc4go/internal/s7/Driver.go
@@ -21,10 +21,10 @@ package s7
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"net/url"
 
 	"github.com/apache/plc4x/plc4go/pkg/api"
-	"github.com/apache/plc4x/plc4go/spi"
 	_default "github.com/apache/plc4x/plc4go/spi/default"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/pkg/errors"
@@ -33,14 +33,14 @@ import (
 
 type Driver struct {
 	_default.DefaultDriver
-	tm                      spi.RequestTransactionManager
+	tm                      transactions.RequestTransactionManager
 	awaitSetupComplete      bool
 	awaitDisconnectComplete bool
 }
 
 func NewDriver() plc4go.PlcDriver {
 	driver := &Driver{
-		tm:                      spi.NewRequestTransactionManager(1),
+		tm:                      transactions.NewRequestTransactionManager(1),
 		awaitSetupComplete:      true,
 		awaitDisconnectComplete: true,
 	}
diff --git a/plc4go/internal/s7/Reader.go b/plc4go/internal/s7/Reader.go
index 45b8ccfa19..4a99674f62 100644
--- a/plc4go/internal/s7/Reader.go
+++ b/plc4go/internal/s7/Reader.go
@@ -21,6 +21,7 @@ package s7
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"time"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
@@ -37,10 +38,10 @@ import (
 type Reader struct {
 	tpduGenerator *TpduGenerator
 	messageCodec  spi.MessageCodec
-	tm            spi.RequestTransactionManager
+	tm            transactions.RequestTransactionManager
 }
 
-func NewReader(tpduGenerator *TpduGenerator, messageCodec spi.MessageCodec, tm spi.RequestTransactionManager) *Reader {
+func NewReader(tpduGenerator *TpduGenerator, messageCodec spi.MessageCodec, tm transactions.RequestTransactionManager) *Reader {
 	return &Reader{
 		tpduGenerator: tpduGenerator,
 		messageCodec:  messageCodec,
@@ -101,7 +102,7 @@ func (m *Reader) Read(ctx context.Context, readRequest apiModel.PlcReadRequest)
 		)
 		// Start a new request-transaction (Is ended in the response-handler)
 		transaction := m.tm.StartTransaction()
-		transaction.Submit(func(transaction spi.RequestTransaction) {
+		transaction.Submit(func(transaction transactions.RequestTransaction) {
 
 			// Send the  over the wire
 			log.Trace().Msg("Send ")
diff --git a/plc4go/internal/s7/Writer.go b/plc4go/internal/s7/Writer.go
index 171fe0660e..2bf9a8f3b5 100644
--- a/plc4go/internal/s7/Writer.go
+++ b/plc4go/internal/s7/Writer.go
@@ -21,6 +21,7 @@ package s7
 
 import (
 	"context"
+	"github.com/apache/plc4x/plc4go/spi/transactions"
 	"time"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
@@ -36,10 +37,10 @@ import (
 type Writer struct {
 	tpduGenerator *TpduGenerator
 	messageCodec  spi.MessageCodec
-	tm            spi.RequestTransactionManager
+	tm            transactions.RequestTransactionManager
 }
 
-func NewWriter(tpduGenerator *TpduGenerator, messageCodec spi.MessageCodec, tm spi.RequestTransactionManager) Writer {
+func NewWriter(tpduGenerator *TpduGenerator, messageCodec spi.MessageCodec, tm transactions.RequestTransactionManager) Writer {
 	return Writer{
 		tpduGenerator: tpduGenerator,
 		messageCodec:  messageCodec,
@@ -98,7 +99,7 @@ func (m Writer) Write(ctx context.Context, writeRequest apiModel.PlcWriteRequest
 
 		// Start a new request-transaction (Is ended in the response-handler)
 		transaction := m.tm.StartTransaction()
-		transaction.Submit(func(transaction spi.RequestTransaction) {
+		transaction.Submit(func(transaction transactions.RequestTransaction) {
 			// Send the  over the wire
 			if err := m.messageCodec.SendRequest(ctx, tpktPacket, func(message spi.Message) bool {
 				tpktPacket, ok := message.(readWriteModel.TPKTPacketExactly)
diff --git a/plc4go/pkg/api/driver.go b/plc4go/pkg/api/driver.go
index 293ddad294..d7a405b601 100644
--- a/plc4go/pkg/api/driver.go
+++ b/plc4go/pkg/api/driver.go
@@ -48,7 +48,7 @@ type PlcDriver interface {
 	GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan PlcConnectionConnectResult
 	// GetConnectionWithContext Establishes a connection to a given PLC using the information in the connectionString
 	// FIXME: this leaks spi in the signature move to spi driver or create interfaces. Can also be done by moving spi in a proper module
-	GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan PlcConnectionConnectResult
+	GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, driverOptions map[string][]string) <-chan PlcConnectionConnectResult
 
 	// SupportsDiscovery returns true if this driver supports discovery
 	SupportsDiscovery() bool
diff --git a/plc4go/pkg/api/mock_PlcDriver_test.go b/plc4go/pkg/api/mock_PlcDriver_test.go
index c1a1c71636..fb2f548262 100644
--- a/plc4go/pkg/api/mock_PlcDriver_test.go
+++ b/plc4go/pkg/api/mock_PlcDriver_test.go
@@ -292,13 +292,13 @@ func (_c *MockPlcDriver_GetConnection_Call) RunAndReturn(run func(url.URL, map[s
 	return _c
 }
 
-// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, _a3
-func (_m *MockPlcDriver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string) <-chan PlcConnectionConnectResult {
-	ret := _m.Called(ctx, transportUrl, _a2, _a3)
+// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, driverOptions
+func (_m *MockPlcDriver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string) <-chan PlcConnectionConnectResult {
+	ret := _m.Called(ctx, transportUrl, _a2, driverOptions)
 
 	var r0 <-chan PlcConnectionConnectResult
 	if rf, ok := ret.Get(0).(func(context.Context, url.URL, map[string]transports.Transport, map[string][]string) <-chan PlcConnectionConnectResult); ok {
-		r0 = rf(ctx, transportUrl, _a2, _a3)
+		r0 = rf(ctx, transportUrl, _a2, driverOptions)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(<-chan PlcConnectionConnectResult)
@@ -317,12 +317,12 @@ type MockPlcDriver_GetConnectionWithContext_Call struct {
 //   - ctx context.Context
 //   - transportUrl url.URL
 //   - _a2 map[string]transports.Transport
-//   - _a3 map[string][]string
-func (_e *MockPlcDriver_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, _a3 interface{}) *MockPlcDriver_GetConnectionWithContext_Call {
-	return &MockPlcDriver_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, _a3)}
+//   - driverOptions map[string][]string
+func (_e *MockPlcDriver_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, driverOptions interface{}) *MockPlcDriver_GetConnectionWithContext_Call {
+	return &MockPlcDriver_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, driverOptions)}
 }
 
-func (_c *MockPlcDriver_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string)) *MockPlcDriver_GetConnectionWithContext_Call {
+func (_c *MockPlcDriver_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string)) *MockPlcDriver_GetConnectionWithContext_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(url.URL), args[2].(map[string]transports.Transport), args[3].(map[string][]string))
 	})
diff --git a/plc4go/pkg/api/mock_Transport_test.go b/plc4go/pkg/api/mock_Transport_test.go
index a3ac4c196b..c42f59e91f 100644
--- a/plc4go/pkg/api/mock_Transport_test.go
+++ b/plc4go/pkg/api/mock_Transport_test.go
@@ -22,10 +22,12 @@
 package plc4go
 
 import (
-	url "net/url"
+	options "github.com/apache/plc4x/plc4go/spi/options"
+	mock "github.com/stretchr/testify/mock"
 
 	transports "github.com/apache/plc4x/plc4go/spi/transports"
-	mock "github.com/stretchr/testify/mock"
+
+	url "net/url"
 )
 
 // MockTransport is an autogenerated mock type for the Transport type
@@ -41,25 +43,32 @@ func (_m *MockTransport) EXPECT() *MockTransport_Expecter {
 	return &MockTransport_Expecter{mock: &_m.Mock}
 }
 
-// CreateTransportInstance provides a mock function with given fields: transportUrl, options
-func (_m *MockTransport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
-	ret := _m.Called(transportUrl, options)
+// CreateTransportInstance provides a mock function with given fields: transportUrl, _a1, _options
+func (_m *MockTransport) CreateTransportInstance(transportUrl url.URL, _a1 map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
+	_va := make([]interface{}, len(_options))
+	for _i := range _options {
+		_va[_i] = _options[_i]
+	}
+	var _ca []interface{}
+	_ca = append(_ca, transportUrl, _a1)
+	_ca = append(_ca, _va...)
+	ret := _m.Called(_ca...)
 
 	var r0 transports.TransportInstance
 	var r1 error
-	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string) (transports.TransportInstance, error)); ok {
-		return rf(transportUrl, options)
+	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string, ...options.WithOption) (transports.TransportInstance, error)); ok {
+		return rf(transportUrl, _a1, _options...)
 	}
-	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string) transports.TransportInstance); ok {
-		r0 = rf(transportUrl, options)
+	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string, ...options.WithOption) transports.TransportInstance); ok {
+		r0 = rf(transportUrl, _a1, _options...)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(transports.TransportInstance)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(url.URL, map[string][]string) error); ok {
-		r1 = rf(transportUrl, options)
+	if rf, ok := ret.Get(1).(func(url.URL, map[string][]string, ...options.WithOption) error); ok {
+		r1 = rf(transportUrl, _a1, _options...)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -74,14 +83,22 @@ type MockTransport_CreateTransportInstance_Call struct {
 
 // CreateTransportInstance is a helper method to define mock.On call
 //   - transportUrl url.URL
-//   - options map[string][]string
-func (_e *MockTransport_Expecter) CreateTransportInstance(transportUrl interface{}, options interface{}) *MockTransport_CreateTransportInstance_Call {
-	return &MockTransport_CreateTransportInstance_Call{Call: _e.mock.On("CreateTransportInstance", transportUrl, options)}
+//   - _a1 map[string][]string
+//   - _options ...options.WithOption
+func (_e *MockTransport_Expecter) CreateTransportInstance(transportUrl interface{}, _a1 interface{}, _options ...interface{}) *MockTransport_CreateTransportInstance_Call {
+	return &MockTransport_CreateTransportInstance_Call{Call: _e.mock.On("CreateTransportInstance",
+		append([]interface{}{transportUrl, _a1}, _options...)...)}
 }
 
-func (_c *MockTransport_CreateTransportInstance_Call) Run(run func(transportUrl url.URL, options map[string][]string)) *MockTransport_CreateTransportInstance_Call {
+func (_c *MockTransport_CreateTransportInstance_Call) Run(run func(transportUrl url.URL, _a1 map[string][]string, _options ...options.WithOption)) *MockTransport_CreateTransportInstance_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(url.URL), args[1].(map[string][]string))
+		variadicArgs := make([]options.WithOption, len(args)-2)
+		for i, a := range args[2:] {
+			if a != nil {
+				variadicArgs[i] = a.(options.WithOption)
+			}
+		}
+		run(args[0].(url.URL), args[1].(map[string][]string), variadicArgs...)
 	})
 	return _c
 }
@@ -91,7 +108,7 @@ func (_c *MockTransport_CreateTransportInstance_Call) Return(_a0 transports.Tran
 	return _c
 }
 
-func (_c *MockTransport_CreateTransportInstance_Call) RunAndReturn(run func(url.URL, map[string][]string) (transports.TransportInstance, error)) *MockTransport_CreateTransportInstance_Call {
+func (_c *MockTransport_CreateTransportInstance_Call) RunAndReturn(run func(url.URL, map[string][]string, ...options.WithOption) (transports.TransportInstance, error)) *MockTransport_CreateTransportInstance_Call {
 	_c.Call.Return(run)
 	return _c
 }
diff --git a/plc4go/protocols/cbus/readwrite/model/StaticHelper.go b/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
index 100b1f4e41..e219dddbff 100644
--- a/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
+++ b/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
@@ -21,10 +21,11 @@ package model
 
 import (
 	"encoding/hex"
+
 	"github.com/apache/plc4x/plc4go/spi"
 	"github.com/apache/plc4x/plc4go/spi/utils"
+
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 )
 
 func ReadAndValidateChecksum(readBuffer utils.ReadBuffer, message spi.Message, srchk bool) (Checksum, error) {
@@ -140,7 +141,7 @@ func readBytesFromHex(logicalName string, readBuffer utils.ReadBuffer, srchk boo
 		readBuffer.Reset(readBuffer.GetPos() - 2)
 		rawBytes = rawBytes[:len(rawBytes)-1]
 	}
-	log.Trace().Msgf("%d bytes decoded", n)
+	Plc4xModelLog.Trace().Msgf("%d bytes decoded", n)
 	return rawBytes, nil
 }
 
@@ -174,7 +175,7 @@ func writeToHex(logicalName string, writeBuffer utils.WriteBuffer, bytesToWrite
 	// usually you use hex.Encode but we want the encoding in uppercase
 	//n := hex.Encode(hexBytes, wbbb.GetBytes())
 	n := encodeHexUpperCase(hexBytes, bytesToWrite)
-	log.Trace().Msgf("%d bytes encoded", n)
+	Plc4xModelLog.Trace().Msgf("%d bytes encoded", n)
 	return writeBuffer.WriteByteArray(logicalName, hexBytes)
 }
 
diff --git a/plc4go/spi/default/DefaultCodec.go b/plc4go/spi/default/DefaultCodec.go
index 5cf97068e6..f5be14b852 100644
--- a/plc4go/spi/default/DefaultCodec.go
+++ b/plc4go/spi/default/DefaultCodec.go
@@ -22,18 +22,17 @@ package _default
 import (
 	"context"
 	"fmt"
-	"github.com/apache/plc4x/plc4go/spi/utils"
 	"runtime/debug"
 	"time"
 
-	"github.com/apache/plc4x/plc4go/spi/options"
-
 	"github.com/apache/plc4x/plc4go/pkg/api/config"
 	"github.com/apache/plc4x/plc4go/spi"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
+	"github.com/apache/plc4x/plc4go/spi/utils"
+
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog"
-	"github.com/rs/zerolog/log"
 )
 
 // DefaultCodecRequirements adds required methods to MessageCodec that are needed when using DefaultCodec
@@ -84,25 +83,29 @@ type defaultCodec struct {
 	expectations                  []spi.Expectation
 	running                       bool
 	customMessageHandling         func(codec DefaultCodecRequirements, message spi.Message) bool
+
+	log zerolog.Logger
 }
 
-func buildDefaultCodec(defaultCodecRequirements DefaultCodecRequirements, transportInstance transports.TransportInstance, options ...options.WithOption) DefaultCodec {
+func buildDefaultCodec(defaultCodecRequirements DefaultCodecRequirements, transportInstance transports.TransportInstance, _options ...options.WithOption) DefaultCodec {
 	var customMessageHandler func(codec DefaultCodecRequirements, message spi.Message) bool
+	var logger = options.ExtractCustomLogger(_options...)
 
-	for _, option := range options {
-		switch option.(type) {
+	for _, option := range _options {
+		switch option := option.(type) {
 		case withCustomMessageHandler:
-			customMessageHandler = option.(withCustomMessageHandler).customMessageHandler
+			customMessageHandler = option.customMessageHandler
 		}
 	}
 
 	return &defaultCodec{
-		defaultCodecRequirements,
-		transportInstance,
-		make(chan spi.Message),
-		[]spi.Expectation{},
-		false,
-		customMessageHandler,
+		DefaultCodecRequirements:      defaultCodecRequirements,
+		transportInstance:             transportInstance,
+		defaultIncomingMessageChannel: make(chan spi.Message),
+		expectations:                  []spi.Expectation{},
+		running:                       false,
+		customMessageHandling:         customMessageHandler,
+		log:                           logger,
 	}
 }
 
@@ -149,17 +152,17 @@ func (m *defaultCodec) Connect() error {
 }
 
 func (m *defaultCodec) ConnectWithContext(ctx context.Context) error {
-	log.Trace().Msg("Connecting")
+	m.log.Trace().Msg("Connecting")
 	if !m.transportInstance.IsConnected() {
 		if err := m.transportInstance.ConnectWithContext(ctx); err != nil {
 			return err
 		}
 	} else {
-		log.Info().Msg("Transport instance already connected")
+		m.log.Info().Msg("Transport instance already connected")
 	}
 
 	if !m.running {
-		log.Debug().Msg("Message codec currently not running, starting worker now")
+		m.log.Debug().Msg("Message codec currently not running, starting worker now")
 		go m.Work(m.DefaultCodecRequirements)
 	}
 	m.running = true
@@ -167,7 +170,7 @@ func (m *defaultCodec) ConnectWithContext(ctx context.Context) error {
 }
 
 func (m *defaultCodec) Disconnect() error {
-	log.Trace().Msg("Disconnecting")
+	m.log.Trace().Msg("Disconnecting")
 	m.running = false
 	return m.transportInstance.Close()
 }
@@ -192,7 +195,7 @@ func (m *defaultCodec) SendRequest(ctx context.Context, message spi.Message, acc
 	if err := ctx.Err(); err != nil {
 		return errors.Wrap(err, "Not sending message as context is aborted")
 	}
-	log.Trace().Msg("Sending request")
+	m.log.Trace().Msg("Sending request")
 	// Send the actual message
 	err := m.Send(message)
 	if err != nil {
@@ -212,7 +215,7 @@ func (m *defaultCodec) TimeoutExpectations(now time.Time) {
 			// Call the error handler.
 			go func(expectation spi.Expectation) {
 				if err := expectation.GetHandleError()(utils.NewTimeoutError(now.Sub(expectation.GetExpiration()))); err != nil {
-					log.Error().Err(err).Msg("Got an error handling error on expectation")
+					m.log.Error().Err(err).Msg("Got an error handling error on expectation")
 				}
 			}(expectation)
 			continue
@@ -223,7 +226,7 @@ func (m *defaultCodec) TimeoutExpectations(now time.Time) {
 			i--
 			go func(expectation spi.Expectation) {
 				if err := expectation.GetHandleError()(err); err != nil {
-					log.Error().Err(err).Msg("Got an error handling error on expectation")
+					m.log.Error().Err(err).Msg("Got an error handling error on expectation")
 				}
 			}(expectation)
 			continue
@@ -233,12 +236,12 @@ func (m *defaultCodec) TimeoutExpectations(now time.Time) {
 
 func (m *defaultCodec) HandleMessages(message spi.Message) bool {
 	messageHandled := false
-	log.Trace().Msgf("Current number of expectations: %d", len(m.expectations))
+	m.log.Trace().Msgf("Current number of expectations: %d", len(m.expectations))
 	for index, expectation := range m.expectations {
 		// Check if the current message matches the expectations
 		// If it does, let it handle the message.
 		if accepts := expectation.GetAcceptsMessage()(message); accepts {
-			log.Debug().Stringer("expectation", expectation).Msg("accepts message")
+			m.log.Debug().Stringer("expectation", expectation).Msg("accepts message")
 			// TODO: decouple from worker thread
 			err := expectation.GetHandleMessage()(message)
 			if err != nil {
@@ -246,7 +249,7 @@ func (m *defaultCodec) HandleMessages(message spi.Message) bool {
 				// TODO: decouple from worker thread
 				err := expectation.GetHandleError()(err)
 				if err != nil {
-					log.Error().Err(err).Msg("Got an error handling error on expectation")
+					m.log.Error().Err(err).Msg("Got an error handling error on expectation")
 				}
 				continue
 			}
@@ -263,7 +266,7 @@ func (m *defaultCodec) HandleMessages(message spi.Message) bool {
 }
 
 func (m *defaultCodec) Work(codec DefaultCodecRequirements) {
-	workerLog := log.With().Logger()
+	workerLog := m.log.With().Logger()
 	if !config.TraceDefaultMessageCodecWorker {
 		workerLog = zerolog.Nop()
 	}
@@ -271,7 +274,7 @@ func (m *defaultCodec) Work(codec DefaultCodecRequirements) {
 	defer func(workerLog zerolog.Logger) {
 		if err := recover(); err != nil {
 			// TODO: If this is an error, cast it to an error and log it with "Err(err)"
-			log.Error().Msgf("recovered from: %#v at %s", err, string(debug.Stack()))
+			m.log.Error().Msgf("recovered from: %#v at %s", err, string(debug.Stack()))
 		}
 		if m.running {
 			workerLog.Warn().Msg("Keep running")
diff --git a/plc4go/spi/default/DefaultConnection.go b/plc4go/spi/default/DefaultConnection.go
index c703f035ca..492ae8be56 100644
--- a/plc4go/spi/default/DefaultConnection.go
+++ b/plc4go/spi/default/DefaultConnection.go
@@ -21,16 +21,15 @@ package _default
 
 import (
 	"context"
+	"github.com/rs/zerolog"
 	"time"
 
-	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
-
 	"github.com/apache/plc4x/plc4go/pkg/api"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	"github.com/apache/plc4x/plc4go/spi"
 	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
+	"github.com/pkg/errors"
 )
 
 // DefaultConnectionRequirements defines the required at a implementing connection when using DefaultConnection
@@ -152,14 +151,16 @@ type defaultConnection struct {
 	connected    bool
 	tagHandler   spi.PlcTagHandler
 	valueHandler spi.PlcValueHandler
+
+	log zerolog.Logger
 }
 
-func buildDefaultConnection(requirements DefaultConnectionRequirements, options ...options.WithOption) DefaultConnection {
+func buildDefaultConnection(requirements DefaultConnectionRequirements, _options ...options.WithOption) DefaultConnection {
 	defaultTtl := time.Second * 10
 	var tagHandler spi.PlcTagHandler
 	var valueHandler spi.PlcValueHandler
 
-	for _, option := range options {
+	for _, option := range _options {
 		switch option.(type) {
 		case withDefaultTtl:
 			defaultTtl = option.(withDefaultTtl).defaultTtl
@@ -171,11 +172,13 @@ func buildDefaultConnection(requirements DefaultConnectionRequirements, options
 	}
 
 	return &defaultConnection{
-		requirements,
-		defaultTtl,
-		false,
-		tagHandler,
-		valueHandler,
+		DefaultConnectionRequirements: requirements,
+		defaultTtl:                    defaultTtl,
+		connected:                     false,
+		tagHandler:                    tagHandler,
+		valueHandler:                  valueHandler,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
@@ -233,7 +236,7 @@ func (d *defaultConnection) Connect() <-chan plc4go.PlcConnectionConnectResult {
 }
 
 func (d *defaultConnection) ConnectWithContext(ctx context.Context) <-chan plc4go.PlcConnectionConnectResult {
-	log.Trace().Msg("Connecting")
+	d.log.Trace().Msg("Connecting")
 	ch := make(chan plc4go.PlcConnectionConnectResult, 1)
 	go func() {
 		defer func() {
@@ -250,7 +253,7 @@ func (d *defaultConnection) ConnectWithContext(ctx context.Context) <-chan plc4g
 }
 
 func (d *defaultConnection) BlockingClose() {
-	log.Trace().Msg("blocking close connection")
+	d.log.Trace().Msg("blocking close connection")
 	closeResults := d.GetConnection().Close()
 	timeout := time.NewTimer(d.GetTtl())
 	d.SetConnected(false)
@@ -267,9 +270,9 @@ func (d *defaultConnection) BlockingClose() {
 }
 
 func (d *defaultConnection) Close() <-chan plc4go.PlcConnectionCloseResult {
-	log.Trace().Msg("close connection")
+	d.log.Trace().Msg("close connection")
 	if err := d.GetMessageCodec().Disconnect(); err != nil {
-		log.Warn().Err(err).Msg("Error disconnecting message code")
+		d.log.Warn().Err(err).Msg("Error disconnecting message code")
 	}
 	err := d.GetTransportInstance().Close()
 	d.SetConnected(false)
diff --git a/plc4go/spi/default/DefaultDriver.go b/plc4go/spi/default/DefaultDriver.go
index f654f65a58..42f4d18d77 100644
--- a/plc4go/spi/default/DefaultDriver.go
+++ b/plc4go/spi/default/DefaultDriver.go
@@ -33,7 +33,7 @@ import (
 )
 
 type DefaultDriverRequirements interface {
-	GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult
+	GetConnectionWithContext(ctx context.Context, transportUrl url.URL, transports map[string]transports.Transport, driverOptions map[string][]string) <-chan plc4go.PlcConnectionConnectResult
 	DiscoverWithContext(callback context.Context, event func(event apiModel.PlcDiscoveryItem), discoveryOptions ...options.WithDiscoveryOption) error
 }
 
diff --git a/plc4go/spi/default/mock_DefaultDriverRequirements_test.go b/plc4go/spi/default/mock_DefaultDriverRequirements_test.go
index 021d730aec..9c12bf0aee 100644
--- a/plc4go/spi/default/mock_DefaultDriverRequirements_test.go
+++ b/plc4go/spi/default/mock_DefaultDriverRequirements_test.go
@@ -107,13 +107,13 @@ func (_c *MockDefaultDriverRequirements_DiscoverWithContext_Call) RunAndReturn(r
 	return _c
 }
 
-// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, _a3
-func (_m *MockDefaultDriverRequirements) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
-	ret := _m.Called(ctx, transportUrl, _a2, _a3)
+// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, driverOptions
+func (_m *MockDefaultDriverRequirements) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	ret := _m.Called(ctx, transportUrl, _a2, driverOptions)
 
 	var r0 <-chan plc4go.PlcConnectionConnectResult
 	if rf, ok := ret.Get(0).(func(context.Context, url.URL, map[string]transports.Transport, map[string][]string) <-chan plc4go.PlcConnectionConnectResult); ok {
-		r0 = rf(ctx, transportUrl, _a2, _a3)
+		r0 = rf(ctx, transportUrl, _a2, driverOptions)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(<-chan plc4go.PlcConnectionConnectResult)
@@ -132,12 +132,12 @@ type MockDefaultDriverRequirements_GetConnectionWithContext_Call struct {
 //   - ctx context.Context
 //   - transportUrl url.URL
 //   - _a2 map[string]transports.Transport
-//   - _a3 map[string][]string
-func (_e *MockDefaultDriverRequirements_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, _a3 interface{}) *MockDefaultDriverRequirements_GetConnectionWithContext_Call {
-	return &MockDefaultDriverRequirements_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, _a3)}
+//   - driverOptions map[string][]string
+func (_e *MockDefaultDriverRequirements_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, driverOptions interface{}) *MockDefaultDriverRequirements_GetConnectionWithContext_Call {
+	return &MockDefaultDriverRequirements_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, driverOptions)}
 }
 
-func (_c *MockDefaultDriverRequirements_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string)) *MockDefaultDriverRequirements_GetConnectionWithContext_Call {
+func (_c *MockDefaultDriverRequirements_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string)) *MockDefaultDriverRequirements_GetConnectionWithContext_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(url.URL), args[2].(map[string]transports.Transport), args[3].(map[string][]string))
 	})
diff --git a/plc4go/spi/default/mock_DefaultDriver_test.go b/plc4go/spi/default/mock_DefaultDriver_test.go
index 45d7a52da9..f3fcadec19 100644
--- a/plc4go/spi/default/mock_DefaultDriver_test.go
+++ b/plc4go/spi/default/mock_DefaultDriver_test.go
@@ -296,13 +296,13 @@ func (_c *MockDefaultDriver_GetConnection_Call) RunAndReturn(run func(url.URL, m
 	return _c
 }
 
-// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, _a3
-func (_m *MockDefaultDriver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
-	ret := _m.Called(ctx, transportUrl, _a2, _a3)
+// GetConnectionWithContext provides a mock function with given fields: ctx, transportUrl, _a2, driverOptions
+func (_m *MockDefaultDriver) GetConnectionWithContext(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	ret := _m.Called(ctx, transportUrl, _a2, driverOptions)
 
 	var r0 <-chan plc4go.PlcConnectionConnectResult
 	if rf, ok := ret.Get(0).(func(context.Context, url.URL, map[string]transports.Transport, map[string][]string) <-chan plc4go.PlcConnectionConnectResult); ok {
-		r0 = rf(ctx, transportUrl, _a2, _a3)
+		r0 = rf(ctx, transportUrl, _a2, driverOptions)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(<-chan plc4go.PlcConnectionConnectResult)
@@ -321,12 +321,12 @@ type MockDefaultDriver_GetConnectionWithContext_Call struct {
 //   - ctx context.Context
 //   - transportUrl url.URL
 //   - _a2 map[string]transports.Transport
-//   - _a3 map[string][]string
-func (_e *MockDefaultDriver_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, _a3 interface{}) *MockDefaultDriver_GetConnectionWithContext_Call {
-	return &MockDefaultDriver_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, _a3)}
+//   - driverOptions map[string][]string
+func (_e *MockDefaultDriver_Expecter) GetConnectionWithContext(ctx interface{}, transportUrl interface{}, _a2 interface{}, driverOptions interface{}) *MockDefaultDriver_GetConnectionWithContext_Call {
+	return &MockDefaultDriver_GetConnectionWithContext_Call{Call: _e.mock.On("GetConnectionWithContext", ctx, transportUrl, _a2, driverOptions)}
 }
 
-func (_c *MockDefaultDriver_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, _a3 map[string][]string)) *MockDefaultDriver_GetConnectionWithContext_Call {
+func (_c *MockDefaultDriver_GetConnectionWithContext_Call) Run(run func(ctx context.Context, transportUrl url.URL, _a2 map[string]transports.Transport, driverOptions map[string][]string)) *MockDefaultDriver_GetConnectionWithContext_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(url.URL), args[2].(map[string]transports.Transport), args[3].(map[string][]string))
 	})
diff --git a/plc4go/spi/mock_requirements.go b/plc4go/spi/mock_requirements.go
index c19da79323..d5d13452a4 100644
--- a/plc4go/spi/mock_requirements.go
+++ b/plc4go/spi/mock_requirements.go
@@ -20,12 +20,12 @@
 package spi
 
 import (
-	"github.com/apache/plc4x/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/spi/pool"
 )
 
 // Note this file is a Helper for mockery to generate use mocks from other package
 
 // Deprecated: don't use it in productive code
 type CompletionFuture interface {
-	utils.CompletionFuture
+	pool.CompletionFuture
 }
diff --git a/plc4go/spi/options/Option.go b/plc4go/spi/options/Option.go
index 1a242d5593..772d7bd8d9 100644
--- a/plc4go/spi/options/Option.go
+++ b/plc4go/spi/options/Option.go
@@ -19,6 +19,8 @@
 
 package options
 
+import "github.com/rs/zerolog"
+
 // WithOption is a marker interface for options supplied by the builders like WithDefaultTtl
 type WithOption interface {
 	isOption() bool
@@ -31,3 +33,36 @@ type Option struct {
 func (_ Option) isOption() bool {
 	return true
 }
+
+// WithCustomLogger is a global option to supply a custom logger
+func WithCustomLogger(logger zerolog.Logger) WithOption {
+	return withCustomLogger{logger: logger}
+}
+
+// ExtractCustomLogger can be used to extract the custom logger
+func ExtractCustomLogger(options ...WithOption) (customLogger zerolog.Logger) {
+	for _, option := range options {
+		switch option := option.(type) {
+		case withCustomLogger:
+			customLogger = option.logger
+			return
+		}
+	}
+	return
+}
+
+///////////////////////////////////////
+///////////////////////////////////////
+//
+// Internal section
+//
+
+type withCustomLogger struct {
+	Option
+	logger zerolog.Logger
+}
+
+//
+//
+///////////////////////////////////////
+///////////////////////////////////////
diff --git a/plc4go/spi/pool/mock_CompletionFuture_test.go b/plc4go/spi/pool/mock_CompletionFuture_test.go
new file mode 100644
index 0000000000..f395023e6f
--- /dev/null
+++ b/plc4go/spi/pool/mock_CompletionFuture_test.go
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by mockery v2.28.1. DO NOT EDIT.
+
+package pool
+
+import (
+	context "context"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// MockCompletionFuture is an autogenerated mock type for the CompletionFuture type
+type MockCompletionFuture struct {
+	mock.Mock
+}
+
+type MockCompletionFuture_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockCompletionFuture) EXPECT() *MockCompletionFuture_Expecter {
+	return &MockCompletionFuture_Expecter{mock: &_m.Mock}
+}
+
+// AwaitCompletion provides a mock function with given fields: ctx
+func (_m *MockCompletionFuture) AwaitCompletion(ctx context.Context) error {
+	ret := _m.Called(ctx)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+		r0 = rf(ctx)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// MockCompletionFuture_AwaitCompletion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AwaitCompletion'
+type MockCompletionFuture_AwaitCompletion_Call struct {
+	*mock.Call
+}
+
+// AwaitCompletion is a helper method to define mock.On call
+//   - ctx context.Context
+func (_e *MockCompletionFuture_Expecter) AwaitCompletion(ctx interface{}) *MockCompletionFuture_AwaitCompletion_Call {
+	return &MockCompletionFuture_AwaitCompletion_Call{Call: _e.mock.On("AwaitCompletion", ctx)}
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) Run(run func(ctx context.Context)) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context))
+	})
+	return _c
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) Return(_a0 error) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) RunAndReturn(run func(context.Context) error) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Cancel provides a mock function with given fields: interrupt, err
+func (_m *MockCompletionFuture) Cancel(interrupt bool, err error) {
+	_m.Called(interrupt, err)
+}
+
+// MockCompletionFuture_Cancel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cancel'
+type MockCompletionFuture_Cancel_Call struct {
+	*mock.Call
+}
+
+// Cancel is a helper method to define mock.On call
+//   - interrupt bool
+//   - err error
+func (_e *MockCompletionFuture_Expecter) Cancel(interrupt interface{}, err interface{}) *MockCompletionFuture_Cancel_Call {
+	return &MockCompletionFuture_Cancel_Call{Call: _e.mock.On("Cancel", interrupt, err)}
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) Run(run func(interrupt bool, err error)) *MockCompletionFuture_Cancel_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(bool), args[1].(error))
+	})
+	return _c
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) Return() *MockCompletionFuture_Cancel_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) RunAndReturn(run func(bool, error)) *MockCompletionFuture_Cancel_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockCompletionFuture interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockCompletionFuture creates a new instance of MockCompletionFuture. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockCompletionFuture(t mockConstructorTestingTNewMockCompletionFuture) *MockCompletionFuture {
+	mock := &MockCompletionFuture{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/pool/mock_Executor_test.go b/plc4go/spi/pool/mock_Executor_test.go
new file mode 100644
index 0000000000..f7a92e3e80
--- /dev/null
+++ b/plc4go/spi/pool/mock_Executor_test.go
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by mockery v2.28.1. DO NOT EDIT.
+
+package pool
+
+import (
+	context "context"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// MockExecutor is an autogenerated mock type for the Executor type
+type MockExecutor struct {
+	mock.Mock
+}
+
+type MockExecutor_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockExecutor) EXPECT() *MockExecutor_Expecter {
+	return &MockExecutor_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *MockExecutor) Close() error {
+	ret := _m.Called()
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func() error); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// MockExecutor_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type MockExecutor_Close_Call struct {
+	*mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *MockExecutor_Expecter) Close() *MockExecutor_Close_Call {
+	return &MockExecutor_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *MockExecutor_Close_Call) Run(run func()) *MockExecutor_Close_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockExecutor_Close_Call) Return(_a0 error) *MockExecutor_Close_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockExecutor_Close_Call) RunAndReturn(run func() error) *MockExecutor_Close_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// IsRunning provides a mock function with given fields:
+func (_m *MockExecutor) IsRunning() bool {
+	ret := _m.Called()
+
+	var r0 bool
+	if rf, ok := ret.Get(0).(func() bool); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(bool)
+	}
+
+	return r0
+}
+
+// MockExecutor_IsRunning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsRunning'
+type MockExecutor_IsRunning_Call struct {
+	*mock.Call
+}
+
+// IsRunning is a helper method to define mock.On call
+func (_e *MockExecutor_Expecter) IsRunning() *MockExecutor_IsRunning_Call {
+	return &MockExecutor_IsRunning_Call{Call: _e.mock.On("IsRunning")}
+}
+
+func (_c *MockExecutor_IsRunning_Call) Run(run func()) *MockExecutor_IsRunning_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockExecutor_IsRunning_Call) Return(_a0 bool) *MockExecutor_IsRunning_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockExecutor_IsRunning_Call) RunAndReturn(run func() bool) *MockExecutor_IsRunning_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Start provides a mock function with given fields:
+func (_m *MockExecutor) Start() {
+	_m.Called()
+}
+
+// MockExecutor_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
+type MockExecutor_Start_Call struct {
+	*mock.Call
+}
+
+// Start is a helper method to define mock.On call
+func (_e *MockExecutor_Expecter) Start() *MockExecutor_Start_Call {
+	return &MockExecutor_Start_Call{Call: _e.mock.On("Start")}
+}
+
+func (_c *MockExecutor_Start_Call) Run(run func()) *MockExecutor_Start_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockExecutor_Start_Call) Return() *MockExecutor_Start_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockExecutor_Start_Call) RunAndReturn(run func()) *MockExecutor_Start_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Stop provides a mock function with given fields:
+func (_m *MockExecutor) Stop() {
+	_m.Called()
+}
+
+// MockExecutor_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
+type MockExecutor_Stop_Call struct {
+	*mock.Call
+}
+
+// Stop is a helper method to define mock.On call
+func (_e *MockExecutor_Expecter) Stop() *MockExecutor_Stop_Call {
+	return &MockExecutor_Stop_Call{Call: _e.mock.On("Stop")}
+}
+
+func (_c *MockExecutor_Stop_Call) Run(run func()) *MockExecutor_Stop_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockExecutor_Stop_Call) Return() *MockExecutor_Stop_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockExecutor_Stop_Call) RunAndReturn(run func()) *MockExecutor_Stop_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Submit provides a mock function with given fields: ctx, workItemId, runnable
+func (_m *MockExecutor) Submit(ctx context.Context, workItemId int32, runnable Runnable) CompletionFuture {
+	ret := _m.Called(ctx, workItemId, runnable)
+
+	var r0 CompletionFuture
+	if rf, ok := ret.Get(0).(func(context.Context, int32, Runnable) CompletionFuture); ok {
+		r0 = rf(ctx, workItemId, runnable)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(CompletionFuture)
+		}
+	}
+
+	return r0
+}
+
+// MockExecutor_Submit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Submit'
+type MockExecutor_Submit_Call struct {
+	*mock.Call
+}
+
+// Submit is a helper method to define mock.On call
+//   - ctx context.Context
+//   - workItemId int32
+//   - runnable Runnable
+func (_e *MockExecutor_Expecter) Submit(ctx interface{}, workItemId interface{}, runnable interface{}) *MockExecutor_Submit_Call {
+	return &MockExecutor_Submit_Call{Call: _e.mock.On("Submit", ctx, workItemId, runnable)}
+}
+
+func (_c *MockExecutor_Submit_Call) Run(run func(ctx context.Context, workItemId int32, runnable Runnable)) *MockExecutor_Submit_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(int32), args[2].(Runnable))
+	})
+	return _c
+}
+
+func (_c *MockExecutor_Submit_Call) Return(_a0 CompletionFuture) *MockExecutor_Submit_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockExecutor_Submit_Call) RunAndReturn(run func(context.Context, int32, Runnable) CompletionFuture) *MockExecutor_Submit_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockExecutor interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockExecutor creates a new instance of MockExecutor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockExecutor(t mockConstructorTestingTNewMockExecutor) *MockExecutor {
+	mock := &MockExecutor{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/pool/mock_Runnable_test.go b/plc4go/spi/pool/mock_Runnable_test.go
new file mode 100644
index 0000000000..a55e5e962a
--- /dev/null
+++ b/plc4go/spi/pool/mock_Runnable_test.go
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by mockery v2.28.1. DO NOT EDIT.
+
+package pool
+
+import mock "github.com/stretchr/testify/mock"
+
+// MockRunnable is an autogenerated mock type for the Runnable type
+type MockRunnable struct {
+	mock.Mock
+}
+
+type MockRunnable_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockRunnable) EXPECT() *MockRunnable_Expecter {
+	return &MockRunnable_Expecter{mock: &_m.Mock}
+}
+
+// Execute provides a mock function with given fields:
+func (_m *MockRunnable) Execute() {
+	_m.Called()
+}
+
+// MockRunnable_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute'
+type MockRunnable_Execute_Call struct {
+	*mock.Call
+}
+
+// Execute is a helper method to define mock.On call
+func (_e *MockRunnable_Expecter) Execute() *MockRunnable_Execute_Call {
+	return &MockRunnable_Execute_Call{Call: _e.mock.On("Execute")}
+}
+
+func (_c *MockRunnable_Execute_Call) Run(run func()) *MockRunnable_Execute_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockRunnable_Execute_Call) Return() *MockRunnable_Execute_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockRunnable_Execute_Call) RunAndReturn(run func()) *MockRunnable_Execute_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockRunnable interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockRunnable creates a new instance of MockRunnable. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockRunnable(t mockConstructorTestingTNewMockRunnable) *MockRunnable {
+	mock := &MockRunnable{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/testutils/TestUtils.go b/plc4go/spi/testutils/TestUtils.go
index 4dbae796f8..35773412ea 100644
--- a/plc4go/spi/testutils/TestUtils.go
+++ b/plc4go/spi/testutils/TestUtils.go
@@ -24,9 +24,11 @@ import (
 	"github.com/ajankovic/xdiff/parser"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 	"github.com/rs/zerolog/log"
 	"github.com/stretchr/testify/assert"
 	"os"
+	"runtime/debug"
 	"strings"
 	"testing"
 )
@@ -98,3 +100,35 @@ func CompareResults(t *testing.T, actualString []byte, referenceString []byte) e
 	_ = boxSideBySide // TODO: xml too distorted, we need a don't center option
 	return errors.New("there were differences: Expected: \n" + string(referenceString) + "\nBut Got: \n" + string(actualString))
 }
+
+// ProduceTestingLogger produces a logger which redirects to testing.T
+func ProduceTestingLogger(t *testing.T) zerolog.Logger {
+	return zerolog.New(zerolog.NewConsoleWriter(zerolog.ConsoleTestWriter(t)))
+}
+
+// SetToTestingLogger sets logger to  ProduceTestingLogger and resets it on cleanup
+func SetToTestingLogger(t *testing.T, logger *zerolog.Logger) {
+	oldLogger := *logger
+	t.Cleanup(func() {
+		*logger = oldLogger
+	})
+	newLogger := ProduceTestingLogger(t)
+	*logger = newLogger
+}
+
+type _explodingGlobalLogger struct {
+	hardExplode bool
+}
+
+func (e _explodingGlobalLogger) Write(_ []byte) (_ int, err error) {
+	if e.hardExplode {
+		debug.PrintStack()
+		panic("found a global log usage")
+	}
+	return 0, errors.New("found a global log usage")
+}
+
+// ExplodingGlobalLogger Useful to find unredirected logs
+func ExplodingGlobalLogger(hardExplode bool) {
+	log.Logger = zerolog.New(_explodingGlobalLogger{hardExplode: hardExplode})
+}
diff --git a/plc4go/spi/transactions/RequestTransactionManager.go b/plc4go/spi/transactions/RequestTransactionManager.go
index 08865904b1..ff41af79c2 100644
--- a/plc4go/spi/transactions/RequestTransactionManager.go
+++ b/plc4go/spi/transactions/RequestTransactionManager.go
@@ -23,6 +23,9 @@ import (
 	"container/list"
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/pool"
+	"io"
 	"runtime"
 	"sync"
 	"time"
@@ -35,10 +38,10 @@ import (
 	"github.com/rs/zerolog/log"
 )
 
-var sharedExecutorInstance utils.Executor // shared instance
+var sharedExecutorInstance pool.Executor // shared instance
 
 func init() {
-	sharedExecutorInstance = utils.NewFixedSizeExecutor(runtime.NumCPU(), 100, utils.WithExecutorOptionTracerWorkers(config.TraceTransactionManagerWorkers))
+	sharedExecutorInstance = pool.NewFixedSizeExecutor(runtime.NumCPU(), 100, pool.WithExecutorOptionTracerWorkers(config.TraceTransactionManagerWorkers))
 	sharedExecutorInstance.Start()
 }
 
@@ -59,6 +62,9 @@ type RequestTransaction interface {
 
 // RequestTransactionManager handles transactions
 type RequestTransactionManager interface {
+	io.Closer
+	// CloseGraceful gives some time opposed to io.Closer
+	CloseGraceful(timeout time.Duration) error
 	// SetNumberOfConcurrentRequests sets the number of concurrent requests that will be sent out to a device
 	SetNumberOfConcurrentRequests(numberOfConcurrentRequests int)
 	// StartTransaction starts a RequestTransaction
@@ -66,26 +72,27 @@ type RequestTransactionManager interface {
 }
 
 // NewRequestTransactionManager creates a new RequestTransactionManager
-func NewRequestTransactionManager(numberOfConcurrentRequests int, requestTransactionManagerOptions ...RequestTransactionManagerOption) RequestTransactionManager {
+func NewRequestTransactionManager(numberOfConcurrentRequests int, _options ...options.WithOption) RequestTransactionManager {
 	_requestTransactionManager := &requestTransactionManager{
 		numberOfConcurrentRequests: numberOfConcurrentRequests,
 		transactionId:              0,
 		workLog:                    *list.New(),
 		executor:                   sharedExecutorInstance,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
-	for _, requestTransactionManagerOption := range requestTransactionManagerOptions {
-		requestTransactionManagerOption(_requestTransactionManager)
+	for _, option := range _options {
+		switch option := option.(type) {
+		case *withCustomExecutor:
+			_requestTransactionManager.executor = option.executor
+		}
 	}
 	return _requestTransactionManager
 }
 
-type RequestTransactionManagerOption func(requestTransactionManager *requestTransactionManager)
-
 // WithCustomExecutor sets a custom Executor for the RequestTransactionManager
-func WithCustomExecutor(executor utils.Executor) RequestTransactionManagerOption {
-	return func(requestTransactionManager *requestTransactionManager) {
-		requestTransactionManager.executor = executor
-	}
+func WithCustomExecutor(executor pool.Executor) options.WithOption {
+	return &withCustomExecutor{executor: executor}
 }
 
 ///////////////////////////////////////
@@ -94,13 +101,18 @@ func WithCustomExecutor(executor utils.Executor) RequestTransactionManagerOption
 // Internal section
 //
 
+type withCustomExecutor struct {
+	options.Option
+	executor pool.Executor
+}
+
 type requestTransaction struct {
 	parent        *requestTransactionManager
 	transactionId int32
 
 	/** The initial operation to perform to kick off the request */
-	operation        utils.Runnable
-	completionFuture utils.CompletionFuture
+	operation        pool.Runnable
+	completionFuture pool.CompletionFuture
 
 	transactionLog zerolog.Logger
 }
@@ -115,7 +127,11 @@ type requestTransactionManager struct {
 	// Important, this is a FIFO Queue for Fairness!
 	workLog      list.List
 	workLogMutex sync.RWMutex
-	executor     utils.Executor
+	executor     pool.Executor
+
+	shutdown bool
+
+	log zerolog.Logger
 }
 
 //
@@ -172,13 +188,19 @@ func (r *requestTransactionManager) StartTransaction() RequestTransaction {
 	if !config.TraceTransactionManagerTransactions {
 		transactionLogger = zerolog.Nop()
 	}
-	return &requestTransaction{
+	transaction := &requestTransaction{
 		r,
 		currentTransactionId,
 		nil,
 		nil,
 		transactionLogger,
 	}
+	if r.shutdown {
+		if err := r.failRequest(transaction, errors.New("request transaction manager in shutdown")); err != nil {
+			r.log.Error().Err(err).Msg("error shutting down transaction")
+		}
+	}
+	return transaction
 }
 
 func (r *requestTransactionManager) getNumberOfActiveRequests() int {
@@ -215,6 +237,39 @@ func (r *requestTransactionManager) endRequest(transaction *requestTransaction)
 	return nil
 }
 
+func (r *requestTransactionManager) Close() error {
+	return r.CloseGraceful(0)
+}
+
+func (r *requestTransactionManager) CloseGraceful(timeout time.Duration) error {
+	r.shutdown = true
+	if timeout > 0 {
+		timer := time.NewTimer(timeout)
+		defer utils.CleanupTimer(timer)
+		signal := make(chan struct{})
+		go func() {
+			for {
+				if len(r.runningRequests) == 0 {
+					break
+				}
+				time.Sleep(10 * time.Millisecond)
+			}
+			close(signal)
+		}()
+		select {
+		case <-timer.C:
+			log.Warn().Msgf("timout after %d", timeout)
+		case <-signal:
+		}
+	}
+	r.transactionMutex.Lock()
+	defer r.transactionMutex.Unlock()
+	r.workLogMutex.RLock()
+	defer r.workLogMutex.RUnlock()
+	r.runningRequests = nil
+	return r.executor.Close()
+}
+
 func (t *requestTransaction) FailRequest(err error) error {
 	t.transactionLog.Trace().Msg("Fail the request")
 	return t.parent.failRequest(t, err)
diff --git a/plc4go/spi/transactions/RequestTransactionManager_test.go b/plc4go/spi/transactions/RequestTransactionManager_test.go
index c46767ece0..f3d355789b 100644
--- a/plc4go/spi/transactions/RequestTransactionManager_test.go
+++ b/plc4go/spi/transactions/RequestTransactionManager_test.go
@@ -22,7 +22,8 @@ package transactions
 import (
 	"container/list"
 	"context"
-	"github.com/apache/plc4x/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/pool"
 	"github.com/rs/zerolog"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
@@ -33,7 +34,7 @@ import (
 func TestNewRequestTransactionManager(t *testing.T) {
 	type args struct {
 		numberOfConcurrentRequests       int
-		requestTransactionManagerOptions []RequestTransactionManagerOption
+		requestTransactionManagerOptions []options.WithOption
 	}
 	tests := []struct {
 		name string
@@ -51,7 +52,7 @@ func TestNewRequestTransactionManager(t *testing.T) {
 			name: "just create one with option",
 			args: args{
 				numberOfConcurrentRequests: 2,
-				requestTransactionManagerOptions: []RequestTransactionManagerOption{
+				requestTransactionManagerOptions: []options.WithOption{
 					WithCustomExecutor(sharedExecutorInstance),
 				},
 			},
@@ -73,12 +74,12 @@ func TestNewRequestTransactionManager(t *testing.T) {
 
 func TestWithCustomExecutor(t *testing.T) {
 	type args struct {
-		executor utils.Executor
+		executor pool.Executor
 	}
 	tests := []struct {
 		name string
 		args args
-		want RequestTransactionManagerOption
+		want options.WithOption
 	}{
 		{
 			name: "with a option",
@@ -102,7 +103,7 @@ func Test_requestTransactionManager_SetNumberOfConcurrentRequests(t *testing.T)
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	type args struct {
 		numberOfConcurrentRequests int
@@ -144,7 +145,7 @@ func Test_requestTransactionManager_StartTransaction(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	tests := []struct {
 		name   string
@@ -183,7 +184,7 @@ func Test_requestTransactionManager_endRequest(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	type args struct {
 		transaction *requestTransaction
@@ -235,7 +236,7 @@ func Test_requestTransactionManager_failRequest(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	type args struct {
 		transaction *requestTransaction
@@ -287,7 +288,7 @@ func Test_requestTransactionManager_getNumberOfActiveRequests(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	tests := []struct {
 		name   string
@@ -320,7 +321,7 @@ func Test_requestTransactionManager_processWorklog(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	tests := []struct {
 		name   string
@@ -381,7 +382,7 @@ func Test_requestTransactionManager_submitTransaction(t *testing.T) {
 		numberOfConcurrentRequests int
 		transactionId              int32
 		workLog                    list.List
-		executor                   utils.Executor
+		executor                   pool.Executor
 	}
 	type args struct {
 		handle *requestTransaction
@@ -420,8 +421,8 @@ func Test_requestTransaction_AwaitCompletion(t1 *testing.T) {
 	type fields struct {
 		parent           *requestTransactionManager
 		transactionId    int32
-		operation        utils.Runnable
-		completionFuture utils.CompletionFuture
+		operation        pool.Runnable
+		completionFuture pool.CompletionFuture
 		transactionLog   zerolog.Logger
 	}
 	type args struct {
@@ -489,8 +490,8 @@ func Test_requestTransaction_EndRequest(t1 *testing.T) {
 	type fields struct {
 		parent           *requestTransactionManager
 		transactionId    int32
-		operation        utils.Runnable
-		completionFuture utils.CompletionFuture
+		operation        pool.Runnable
+		completionFuture pool.CompletionFuture
 		transactionLog   zerolog.Logger
 	}
 	tests := []struct {
@@ -526,8 +527,8 @@ func Test_requestTransaction_FailRequest(t1 *testing.T) {
 	type fields struct {
 		parent           *requestTransactionManager
 		transactionId    int32
-		operation        utils.Runnable
-		completionFuture utils.CompletionFuture
+		operation        pool.Runnable
+		completionFuture pool.CompletionFuture
 		transactionLog   zerolog.Logger
 	}
 	type args struct {
@@ -577,8 +578,8 @@ func Test_requestTransaction_String(t1 *testing.T) {
 	type fields struct {
 		parent           *requestTransactionManager
 		transactionId    int32
-		operation        utils.Runnable
-		completionFuture utils.CompletionFuture
+		operation        pool.Runnable
+		completionFuture pool.CompletionFuture
 		transactionLog   zerolog.Logger
 	}
 	tests := []struct {
@@ -611,8 +612,8 @@ func Test_requestTransaction_Submit(t1 *testing.T) {
 	type fields struct {
 		parent           *requestTransactionManager
 		transactionId    int32
-		operation        utils.Runnable
-		completionFuture utils.CompletionFuture
+		operation        pool.Runnable
+		completionFuture pool.CompletionFuture
 		transactionLog   zerolog.Logger
 	}
 	type args struct {
diff --git a/plc4go/spi/transactions/mock_RequestTransactionManager_test.go b/plc4go/spi/transactions/mock_RequestTransactionManager_test.go
index f15b138ff3..2b030692bc 100644
--- a/plc4go/spi/transactions/mock_RequestTransactionManager_test.go
+++ b/plc4go/spi/transactions/mock_RequestTransactionManager_test.go
@@ -21,7 +21,11 @@
 
 package transactions
 
-import mock "github.com/stretchr/testify/mock"
+import (
+	time "time"
+
+	mock "github.com/stretchr/testify/mock"
+)
 
 // MockRequestTransactionManager is an autogenerated mock type for the RequestTransactionManager type
 type MockRequestTransactionManager struct {
@@ -36,6 +40,89 @@ func (_m *MockRequestTransactionManager) EXPECT() *MockRequestTransactionManager
 	return &MockRequestTransactionManager_Expecter{mock: &_m.Mock}
 }
 
+// Close provides a mock function with given fields:
+func (_m *MockRequestTransactionManager) Close() error {
+	ret := _m.Called()
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func() error); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// MockRequestTransactionManager_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type MockRequestTransactionManager_Close_Call struct {
+	*mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *MockRequestTransactionManager_Expecter) Close() *MockRequestTransactionManager_Close_Call {
+	return &MockRequestTransactionManager_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *MockRequestTransactionManager_Close_Call) Run(run func()) *MockRequestTransactionManager_Close_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockRequestTransactionManager_Close_Call) Return(_a0 error) *MockRequestTransactionManager_Close_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockRequestTransactionManager_Close_Call) RunAndReturn(run func() error) *MockRequestTransactionManager_Close_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// CloseGraceful provides a mock function with given fields: timeout
+func (_m *MockRequestTransactionManager) CloseGraceful(timeout time.Duration) error {
+	ret := _m.Called(timeout)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(time.Duration) error); ok {
+		r0 = rf(timeout)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// MockRequestTransactionManager_CloseGraceful_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseGraceful'
+type MockRequestTransactionManager_CloseGraceful_Call struct {
+	*mock.Call
+}
+
+// CloseGraceful is a helper method to define mock.On call
+//   - timeout time.Duration
+func (_e *MockRequestTransactionManager_Expecter) CloseGraceful(timeout interface{}) *MockRequestTransactionManager_CloseGraceful_Call {
+	return &MockRequestTransactionManager_CloseGraceful_Call{Call: _e.mock.On("CloseGraceful", timeout)}
+}
+
+func (_c *MockRequestTransactionManager_CloseGraceful_Call) Run(run func(timeout time.Duration)) *MockRequestTransactionManager_CloseGraceful_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(time.Duration))
+	})
+	return _c
+}
+
+func (_c *MockRequestTransactionManager_CloseGraceful_Call) Return(_a0 error) *MockRequestTransactionManager_CloseGraceful_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockRequestTransactionManager_CloseGraceful_Call) RunAndReturn(run func(time.Duration) error) *MockRequestTransactionManager_CloseGraceful_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // SetNumberOfConcurrentRequests provides a mock function with given fields: numberOfConcurrentRequests
 func (_m *MockRequestTransactionManager) SetNumberOfConcurrentRequests(numberOfConcurrentRequests int) {
 	_m.Called(numberOfConcurrentRequests)
diff --git a/plc4go/spi/transactions/mock_requirements.go b/plc4go/spi/transactions/mock_requirements.go
index 4feb95b8de..64f8171934 100644
--- a/plc4go/spi/transactions/mock_requirements.go
+++ b/plc4go/spi/transactions/mock_requirements.go
@@ -20,12 +20,12 @@
 package transactions
 
 import (
-	"github.com/apache/plc4x/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/spi/pool"
 )
 
 // Note this file is a Helper for mockery to generate use mocks from other package
 
 // Deprecated: don't use it in productive code
 type CompletionFuture interface {
-	utils.CompletionFuture
+	pool.CompletionFuture
 }
diff --git a/plc4go/spi/transports/Transport.go b/plc4go/spi/transports/Transport.go
index ea0ad98d74..128c0f1ea2 100644
--- a/plc4go/spi/transports/Transport.go
+++ b/plc4go/spi/transports/Transport.go
@@ -19,7 +19,10 @@
 
 package transports
 
-import "net/url"
+import (
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"net/url"
+)
 
 type Transport interface {
 	// GetTransportCode Get the short code used to identify this transport (As used in the connection string)
@@ -27,5 +30,5 @@ type Transport interface {
 	// GetTransportName Get a human-readable name for this transport
 	GetTransportName() string
 	// CreateTransportInstance creates transport instance
-	CreateTransportInstance(transportUrl url.URL, options map[string][]string) (TransportInstance, error)
+	CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (TransportInstance, error)
 }
diff --git a/plc4go/spi/transports/mock_Transport_test.go b/plc4go/spi/transports/mock_Transport_test.go
index 1637099390..0fe7e0a258 100644
--- a/plc4go/spi/transports/mock_Transport_test.go
+++ b/plc4go/spi/transports/mock_Transport_test.go
@@ -22,9 +22,10 @@
 package transports
 
 import (
-	url "net/url"
-
+	options "github.com/apache/plc4x/plc4go/spi/options"
 	mock "github.com/stretchr/testify/mock"
+
+	url "net/url"
 )
 
 // MockTransport is an autogenerated mock type for the Transport type
@@ -40,25 +41,32 @@ func (_m *MockTransport) EXPECT() *MockTransport_Expecter {
 	return &MockTransport_Expecter{mock: &_m.Mock}
 }
 
-// CreateTransportInstance provides a mock function with given fields: transportUrl, options
-func (_m *MockTransport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (TransportInstance, error) {
-	ret := _m.Called(transportUrl, options)
+// CreateTransportInstance provides a mock function with given fields: transportUrl, _a1, _options
+func (_m *MockTransport) CreateTransportInstance(transportUrl url.URL, _a1 map[string][]string, _options ...options.WithOption) (TransportInstance, error) {
+	_va := make([]interface{}, len(_options))
+	for _i := range _options {
+		_va[_i] = _options[_i]
+	}
+	var _ca []interface{}
+	_ca = append(_ca, transportUrl, _a1)
+	_ca = append(_ca, _va...)
+	ret := _m.Called(_ca...)
 
 	var r0 TransportInstance
 	var r1 error
-	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string) (TransportInstance, error)); ok {
-		return rf(transportUrl, options)
+	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string, ...options.WithOption) (TransportInstance, error)); ok {
+		return rf(transportUrl, _a1, _options...)
 	}
-	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string) TransportInstance); ok {
-		r0 = rf(transportUrl, options)
+	if rf, ok := ret.Get(0).(func(url.URL, map[string][]string, ...options.WithOption) TransportInstance); ok {
+		r0 = rf(transportUrl, _a1, _options...)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(TransportInstance)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(url.URL, map[string][]string) error); ok {
-		r1 = rf(transportUrl, options)
+	if rf, ok := ret.Get(1).(func(url.URL, map[string][]string, ...options.WithOption) error); ok {
+		r1 = rf(transportUrl, _a1, _options...)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -73,14 +81,22 @@ type MockTransport_CreateTransportInstance_Call struct {
 
 // CreateTransportInstance is a helper method to define mock.On call
 //   - transportUrl url.URL
-//   - options map[string][]string
-func (_e *MockTransport_Expecter) CreateTransportInstance(transportUrl interface{}, options interface{}) *MockTransport_CreateTransportInstance_Call {
-	return &MockTransport_CreateTransportInstance_Call{Call: _e.mock.On("CreateTransportInstance", transportUrl, options)}
+//   - _a1 map[string][]string
+//   - _options ...options.WithOption
+func (_e *MockTransport_Expecter) CreateTransportInstance(transportUrl interface{}, _a1 interface{}, _options ...interface{}) *MockTransport_CreateTransportInstance_Call {
+	return &MockTransport_CreateTransportInstance_Call{Call: _e.mock.On("CreateTransportInstance",
+		append([]interface{}{transportUrl, _a1}, _options...)...)}
 }
 
-func (_c *MockTransport_CreateTransportInstance_Call) Run(run func(transportUrl url.URL, options map[string][]string)) *MockTransport_CreateTransportInstance_Call {
+func (_c *MockTransport_CreateTransportInstance_Call) Run(run func(transportUrl url.URL, _a1 map[string][]string, _options ...options.WithOption)) *MockTransport_CreateTransportInstance_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(url.URL), args[1].(map[string][]string))
+		variadicArgs := make([]options.WithOption, len(args)-2)
+		for i, a := range args[2:] {
+			if a != nil {
+				variadicArgs[i] = a.(options.WithOption)
+			}
+		}
+		run(args[0].(url.URL), args[1].(map[string][]string), variadicArgs...)
 	})
 	return _c
 }
@@ -90,7 +106,7 @@ func (_c *MockTransport_CreateTransportInstance_Call) Return(_a0 TransportInstan
 	return _c
 }
 
-func (_c *MockTransport_CreateTransportInstance_Call) RunAndReturn(run func(url.URL, map[string][]string) (TransportInstance, error)) *MockTransport_CreateTransportInstance_Call {
+func (_c *MockTransport_CreateTransportInstance_Call) RunAndReturn(run func(url.URL, map[string][]string, ...options.WithOption) (TransportInstance, error)) *MockTransport_CreateTransportInstance_Call {
 	_c.Call.Return(run)
 	return _c
 }
diff --git a/plc4go/spi/transports/pcap/Transport.go b/plc4go/spi/transports/pcap/Transport.go
index 8bc986a28a..ef455e6364 100644
--- a/plc4go/spi/transports/pcap/Transport.go
+++ b/plc4go/spi/transports/pcap/Transport.go
@@ -23,12 +23,13 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/gopacket/gopacket"
 	"github.com/gopacket/gopacket/layers"
 	"github.com/gopacket/gopacket/pcap"
 	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
+	"github.com/rs/zerolog"
 	"io"
 	"net/url"
 	"strconv"
@@ -45,10 +46,13 @@ const (
 )
 
 type Transport struct {
+	log zerolog.Logger
 }
 
-func NewTransport() *Transport {
-	return &Transport{}
+func NewTransport(_options ...options.WithOption) *Transport {
+	return &Transport{
+		log: options.ExtractCustomLogger(_options...),
+	}
 }
 
 func (m Transport) GetTransportCode() string {
@@ -59,7 +63,7 @@ func (m Transport) GetTransportName() string {
 	return "PCAP(NG) Playback Transport"
 }
 
-func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
+func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
 	var transportType = PCAP
 	if val, ok := options["transport-type"]; ok {
 		transportType = TransportType(val[0])
@@ -77,7 +81,7 @@ func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[str
 		}
 	}
 
-	return NewPcapTransportInstance(transportUrl.Path, transportType, portRange, speedFactor, &m), nil
+	return NewPcapTransportInstance(transportUrl.Path, transportType, portRange, speedFactor, &m, _options...), nil
 }
 
 func (m Transport) String() string {
@@ -95,15 +99,19 @@ type TransportInstance struct {
 	handle        *pcap.Handle
 	mutex         sync.Mutex
 	reader        *bufio.Reader
+
+	log zerolog.Logger
 }
 
-func NewPcapTransportInstance(transportFile string, transportType TransportType, portRange string, speedFactor float32, transport *Transport) *TransportInstance {
+func NewPcapTransportInstance(transportFile string, transportType TransportType, portRange string, speedFactor float32, transport *Transport, _options ...options.WithOption) *TransportInstance {
 	transportInstance := &TransportInstance{
 		transportFile: transportFile,
 		transportType: transportType,
 		portRange:     portRange,
 		speedFactor:   speedFactor,
 		transport:     transport,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 	transportInstance.DefaultBufferedTransportInstance = transports.NewDefaultBufferedTransportInstance(transportInstance)
 	return transportInstance
@@ -132,7 +140,7 @@ func (m *TransportInstance) Connect() error {
 	go func(m *TransportInstance, buffer *bytes.Buffer) {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				m.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
 		packageCount := 0
@@ -140,33 +148,33 @@ func (m *TransportInstance) Connect() error {
 		for m.connected {
 			packetData, captureInfo, err := m.handle.ReadPacketData()
 			packageCount++
-			log.Info().Msgf("Read new package (nr. %d) %#v", packageCount, captureInfo)
+			m.log.Info().Msgf("Read new package (nr. %d) %#v", packageCount, captureInfo)
 			if err != nil {
 				if err == io.EOF {
-					log.Info().Msg("Done reading pcap")
+					m.log.Info().Msg("Done reading pcap")
 					break
 				}
-				log.Warn().Err(err).Msg("Error reading")
+				m.log.Warn().Err(err).Msg("Error reading")
 				m.connected = false
 				return
 			}
 			if lastPacketTime != nil && m.speedFactor != 0 {
 				timeToSleep := captureInfo.Timestamp.Sub(*lastPacketTime)
 				timeToSleep = time.Duration(int64(float64(timeToSleep) / float64(m.speedFactor)))
-				log.Debug().Msgf("Sleeping for %v (Speed factor %fx)", timeToSleep, m.speedFactor)
+				m.log.Debug().Msgf("Sleeping for %v (Speed factor %fx)", timeToSleep, m.speedFactor)
 				time.Sleep(timeToSleep)
 			}
 
 			// Decode a packet
 			packet := gopacket.NewPacket(packetData, layers.LayerTypeEthernet, gopacket.Default)
-			log.Debug().Msgf("Packet dump (nr. %d):\n%s", packageCount, packet.Dump())
+			m.log.Debug().Msgf("Packet dump (nr. %d):\n%s", packageCount, packet.Dump())
 			var payload []byte
 			switch m.transportType {
 			case TCP:
 				if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
 					tcp, _ := tcpLayer.(*layers.TCP)
 					payload = tcp.Payload
-					log.Debug().Msgf("TCP: From src port %d to dst port %d", tcp.SrcPort, tcp.DstPort)
+					m.log.Debug().Msgf("TCP: From src port %d to dst port %d", tcp.SrcPort, tcp.DstPort)
 				} else {
 					continue
 				}
@@ -174,7 +182,7 @@ func (m *TransportInstance) Connect() error {
 				if tcpLayer := packet.Layer(layers.LayerTypeUDP); tcpLayer != nil {
 					udp, _ := tcpLayer.(*layers.UDP)
 					payload = udp.Payload
-					log.Debug().Msgf("UDP: From src port %d to dst port %d", udp.SrcPort, udp.DstPort)
+					m.log.Debug().Msgf("UDP: From src port %d to dst port %d", udp.SrcPort, udp.DstPort)
 				} else {
 					continue
 				}
diff --git a/plc4go/spi/transports/serial/Transport.go b/plc4go/spi/transports/serial/Transport.go
index 6cc0067a39..8640121603 100644
--- a/plc4go/spi/transports/serial/Transport.go
+++ b/plc4go/spi/transports/serial/Transport.go
@@ -22,20 +22,27 @@ package serial
 import (
 	"bufio"
 	"fmt"
-	"github.com/apache/plc4x/plc4go/spi/transports"
-	"github.com/jacobsa/go-serial/serial"
-	"github.com/pkg/errors"
 	"io"
 	"net"
 	"net/url"
 	"strconv"
+
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transports"
+
+	"github.com/jacobsa/go-serial/serial"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 )
 
 type Transport struct {
+	log zerolog.Logger
 }
 
-func NewTransport() *Transport {
-	return &Transport{}
+func NewTransport(_options ...options.WithOption) *Transport {
+	return &Transport{
+		log: options.ExtractCustomLogger(_options...),
+	}
 }
 
 func (m Transport) GetTransportCode() string {
@@ -46,11 +53,11 @@ func (m Transport) GetTransportName() string {
 	return "Serial Transport"
 }
 
-func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
-	return m.CreateTransportInstanceForLocalAddress(transportUrl, options, nil)
+func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
+	return m.CreateTransportInstanceForLocalAddress(transportUrl, options, nil, _options...)
 }
 
-func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL, options map[string][]string, _ *net.UDPAddr) (transports.TransportInstance, error) {
+func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL, options map[string][]string, _ *net.UDPAddr, _options ...options.WithOption) (transports.TransportInstance, error) {
 	var serialPortName = transportUrl.Path
 
 	var baudRate = uint(115200)
@@ -73,7 +80,7 @@ func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL,
 		}
 	}
 
-	return NewTransportInstance(serialPortName, baudRate, connectTimeout, &m), nil
+	return NewTransportInstance(serialPortName, baudRate, connectTimeout, &m, _options...), nil
 }
 
 func (m Transport) String() string {
@@ -88,14 +95,18 @@ type TransportInstance struct {
 	transport      *Transport
 	serialPort     io.ReadWriteCloser
 	reader         *bufio.Reader
+
+	log zerolog.Logger
 }
 
-func NewTransportInstance(serialPortName string, baudRate uint, connectTimeout uint32, transport *Transport) *TransportInstance {
+func NewTransportInstance(serialPortName string, baudRate uint, connectTimeout uint32, transport *Transport, _options ...options.WithOption) *TransportInstance {
 	transportInstance := &TransportInstance{
 		SerialPortName: serialPortName,
 		BaudRate:       baudRate,
 		ConnectTimeout: connectTimeout,
 		transport:      transport,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 	transportInstance.DefaultBufferedTransportInstance = transports.NewDefaultBufferedTransportInstance(transportInstance)
 	return transportInstance
@@ -111,11 +122,11 @@ func (m *TransportInstance) Connect() error {
 	// Add a logging layer ...
 	/*logFile, err := ioutil.TempFile(os.TempDir(), "transport-logger")
 	if err != nil {
-		log.Error().Msg("Error creating file for logging transport requests")
+		m.log.Error().Msg("Error creating file for logging transport requests")
 	} else {
 		fileLogger := zerolog.New(logFile).With().Logger()
 		m.serialPort = utils.NewTransportLogger(m.serialPort, utils.WithLogger(fileLogger))
-		log.Trace().Msgf("Logging Transport to file %s", logFile.Name())
+		m.log.Trace().Msgf("Logging Transport to file %s", logFile.Name())
 	}*/
 	m.reader = bufio.NewReader(m.serialPort)
 
diff --git a/plc4go/spi/transports/tcp/Transport.go b/plc4go/spi/transports/tcp/Transport.go
index b84e8e7932..09c0fd2ba1 100644
--- a/plc4go/spi/transports/tcp/Transport.go
+++ b/plc4go/spi/transports/tcp/Transport.go
@@ -28,12 +28,16 @@ import (
 	"regexp"
 	"strconv"
 
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/utils"
+
 	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 )
 
 type Transport struct {
+	log zerolog.Logger
 }
 
 func NewTransport() *Transport {
@@ -48,7 +52,7 @@ func (m Transport) GetTransportName() string {
 	return "TCP/IP Socket Transport"
 }
 
-func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
+func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
 	connectionStringRegexp := regexp.MustCompile(`^((?P<ip>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})|(?P<hostname>[a-zA-Z0-9.\-]+))(:(?P<port>[0-9]{1,5}))?`)
 	var address string
 	var port int
@@ -85,7 +89,7 @@ func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[str
 		return nil, errors.Wrap(err, "error resolving typ address")
 	}
 
-	return NewTcpTransportInstance(tcpAddr, connectTimeout, &m), nil
+	return NewTcpTransportInstance(tcpAddr, connectTimeout, &m, _options...), nil
 }
 
 func (m Transport) String() string {
@@ -100,13 +104,17 @@ type TransportInstance struct {
 	transport      *Transport
 	tcpConn        net.Conn
 	reader         *bufio.Reader
+
+	log zerolog.Logger
 }
 
-func NewTcpTransportInstance(remoteAddress *net.TCPAddr, connectTimeout uint32, transport *Transport) *TransportInstance {
+func NewTcpTransportInstance(remoteAddress *net.TCPAddr, connectTimeout uint32, transport *Transport, _options ...options.WithOption) *TransportInstance {
 	transportInstance := &TransportInstance{
 		RemoteAddress:  remoteAddress,
 		ConnectTimeout: connectTimeout,
 		transport:      transport,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 	transportInstance.DefaultBufferedTransportInstance = transports.NewDefaultBufferedTransportInstance(transportInstance)
 	return transportInstance
diff --git a/plc4go/spi/transports/test/Transport.go b/plc4go/spi/transports/test/Transport.go
index 995bd969dc..53c3f9383f 100644
--- a/plc4go/spi/transports/test/Transport.go
+++ b/plc4go/spi/transports/test/Transport.go
@@ -23,19 +23,27 @@ import (
 	"bufio"
 	"bytes"
 	"context"
-	"github.com/apache/plc4x/plc4go/spi/transports"
-	"github.com/pkg/errors"
-	"github.com/rs/zerolog/log"
 	"math"
 	"net/url"
+
+	"github.com/apache/plc4x/plc4go/spi/options"
+	"github.com/apache/plc4x/plc4go/spi/transports"
+
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 )
 
 type Transport struct {
 	preregisteredInstances map[url.URL]transports.TransportInstance
+
+	log zerolog.Logger
 }
 
-func NewTransport() *Transport {
-	return &Transport{preregisteredInstances: map[url.URL]transports.TransportInstance{}}
+func NewTransport(_options ...options.WithOption) *Transport {
+	return &Transport{
+		preregisteredInstances: map[url.URL]transports.TransportInstance{},
+		log:                    options.ExtractCustomLogger(_options...),
+	}
 }
 
 func (m *Transport) GetTransportCode() string {
@@ -46,15 +54,15 @@ func (m *Transport) GetTransportName() string {
 	return "Test Transport"
 }
 
-func (m *Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
+func (m *Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
 	if _, ok := options["failTestTransport"]; ok {
 		return nil, errors.New("test transport failed on purpose")
 	}
 	if preregisteredInstance, ok := m.preregisteredInstances[transportUrl]; ok {
-		log.Trace().Msgf("Returning pre registered instance for %v", transportUrl)
+		m.log.Trace().Msgf("Returning pre registered instance for %v", transportUrl)
 		return preregisteredInstance, nil
 	}
-	log.Trace().Msg("create transport instance")
+	m.log.Trace().Msg("create transport instance")
 	return NewTransportInstance(m), nil
 }
 
@@ -76,19 +84,23 @@ type TransportInstance struct {
 	connected        bool
 	transport        *Transport
 	writeInterceptor func(transportInstance *TransportInstance, data []byte)
+
+	log zerolog.Logger
 }
 
-func NewTransportInstance(transport *Transport) *TransportInstance {
+func NewTransportInstance(transport *Transport, _options ...options.WithOption) *TransportInstance {
 	return &TransportInstance{
 		readBuffer:  []byte{},
 		writeBuffer: []byte{},
 		connected:   false,
 		transport:   transport,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 
 func (m *TransportInstance) Connect() error {
-	log.Trace().Msg("Connect")
+	m.log.Trace().Msg("Connect")
 	m.connected = true
 	return nil
 }
@@ -98,7 +110,7 @@ func (m *TransportInstance) ConnectWithContext(_ context.Context) error {
 }
 
 func (m *TransportInstance) Close() error {
-	log.Trace().Msg("Close")
+	m.log.Trace().Msg("Close")
 	m.connected = false
 	return nil
 }
@@ -109,7 +121,7 @@ func (m *TransportInstance) IsConnected() bool {
 
 func (m *TransportInstance) GetNumBytesAvailableInBuffer() (uint32, error) {
 	readableBytes := len(m.readBuffer)
-	log.Trace().Msgf("return number of readable bytes %d", readableBytes)
+	m.log.Trace().Msgf("return number of readable bytes %d", readableBytes)
 	return uint32(readableBytes), nil
 }
 
@@ -129,7 +141,7 @@ func (m *TransportInstance) FillBuffer(until func(pos uint, currentByte byte, re
 
 func (m *TransportInstance) PeekReadableBytes(numBytes uint32) ([]byte, error) {
 	availableBytes := uint32(math.Min(float64(numBytes), float64(len(m.readBuffer))))
-	log.Trace().Msgf("Peek %d readable bytes (%d available bytes)", numBytes, availableBytes)
+	m.log.Trace().Msgf("Peek %d readable bytes (%d available bytes)", numBytes, availableBytes)
 	var err error
 	if availableBytes != numBytes {
 		err = errors.New("not enough bytes available")
@@ -141,7 +153,7 @@ func (m *TransportInstance) PeekReadableBytes(numBytes uint32) ([]byte, error) {
 }
 
 func (m *TransportInstance) Read(numBytes uint32) ([]byte, error) {
-	log.Trace().Msgf("Read num bytes %d", numBytes)
+	m.log.Trace().Msgf("Read num bytes %d", numBytes)
 	data := m.readBuffer[0:int(numBytes)]
 	m.readBuffer = m.readBuffer[int(numBytes):]
 	return data, nil
@@ -155,23 +167,23 @@ func (m *TransportInstance) Write(data []byte) error {
 	if m.writeInterceptor != nil {
 		m.writeInterceptor(m, data)
 	}
-	log.Trace().Msgf("Write data %#x", data)
+	m.log.Trace().Msgf("Write data %#x", data)
 	m.writeBuffer = append(m.writeBuffer, data...)
 	return nil
 }
 
 func (m *TransportInstance) FillReadBuffer(data []byte) {
-	log.Trace().Msgf("FillReadBuffer with %#x", data)
+	m.log.Trace().Msgf("FillReadBuffer with %#x", data)
 	m.readBuffer = append(m.readBuffer, data...)
 }
 
 func (m *TransportInstance) GetNumDrainableBytes() uint32 {
-	log.Trace().Msg("get number of drainable bytes")
+	m.log.Trace().Msg("get number of drainable bytes")
 	return uint32(len(m.writeBuffer))
 }
 
 func (m *TransportInstance) DrainWriteBuffer(numBytes uint32) []byte {
-	log.Trace().Msgf("Drain write buffer with number of bytes %d", numBytes)
+	m.log.Trace().Msgf("Drain write buffer with number of bytes %d", numBytes)
 	data := m.writeBuffer[0:int(numBytes)]
 	m.writeBuffer = m.writeBuffer[int(numBytes):]
 	return data
diff --git a/plc4go/spi/transports/udp/Transport.go b/plc4go/spi/transports/udp/Transport.go
index caefed21ba..2d0ea13768 100644
--- a/plc4go/spi/transports/udp/Transport.go
+++ b/plc4go/spi/transports/udp/Transport.go
@@ -23,10 +23,12 @@ import (
 	"bufio"
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/apache/plc4x/plc4go/spi/transports"
 	"github.com/apache/plc4x/plc4go/spi/utils"
 	"github.com/libp2p/go-reuseport"
 	"github.com/pkg/errors"
+	"github.com/rs/zerolog"
 	"net"
 	"net/url"
 	"regexp"
@@ -34,10 +36,13 @@ import (
 )
 
 type Transport struct {
+	log zerolog.Logger
 }
 
-func NewTransport() *Transport {
-	return &Transport{}
+func NewTransport(_options ...options.WithOption) *Transport {
+	return &Transport{
+		log: options.ExtractCustomLogger(_options...),
+	}
 }
 
 func (m Transport) GetTransportCode() string {
@@ -48,11 +53,11 @@ func (m Transport) GetTransportName() string {
 	return "UDP Datagram Transport"
 }
 
-func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string) (transports.TransportInstance, error) {
-	return m.CreateTransportInstanceForLocalAddress(transportUrl, options, nil)
+func (m Transport) CreateTransportInstance(transportUrl url.URL, options map[string][]string, _options ...options.WithOption) (transports.TransportInstance, error) {
+	return m.CreateTransportInstanceForLocalAddress(transportUrl, options, nil, _options...)
 }
 
-func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL, options map[string][]string, localAddress *net.UDPAddr) (transports.TransportInstance, error) {
+func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL, options map[string][]string, localAddress *net.UDPAddr, _options ...options.WithOption) (transports.TransportInstance, error) {
 	connectionStringRegexp := regexp.MustCompile(`^((?P<ip>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})|(?P<hostname>[a-zA-Z0-9.\-]+))(:(?P<port>[0-9]{1,5}))?`)
 	var remoteAddressString string
 	var remotePort int
@@ -105,7 +110,7 @@ func (m Transport) CreateTransportInstanceForLocalAddress(transportUrl url.URL,
 		return nil, errors.Wrap(err, "error resolving typ address")
 	}
 
-	return NewTransportInstance(localAddress, remoteAddress, connectTimeout, soReUse, &m), nil
+	return NewTransportInstance(localAddress, remoteAddress, connectTimeout, soReUse, &m, _options...), nil
 }
 
 func (m Transport) String() string {
@@ -120,15 +125,19 @@ type TransportInstance struct {
 	transport      *Transport
 	udpConn        *net.UDPConn
 	reader         *bufio.Reader
+
+	log zerolog.Logger
 }
 
-func NewTransportInstance(localAddress *net.UDPAddr, remoteAddress *net.UDPAddr, connectTimeout uint32, soReUse bool, transport *Transport) *TransportInstance {
+func NewTransportInstance(localAddress *net.UDPAddr, remoteAddress *net.UDPAddr, connectTimeout uint32, soReUse bool, transport *Transport, _options ...options.WithOption) *TransportInstance {
 	return &TransportInstance{
 		LocalAddress:   localAddress,
 		RemoteAddress:  remoteAddress,
 		ConnectTimeout: connectTimeout,
 		SoReUse:        soReUse,
 		transport:      transport,
+
+		log: options.ExtractCustomLogger(_options...),
 	}
 }
 


[plc4x] 01/03: refactor(plc4go/spi): move transaction manager to own package

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 09147a8d953167c37a04eaaf49ecf4819f4b9be1
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 31 13:13:00 2023 +0200

    refactor(plc4go/spi): move transaction manager to own package
---
 .../RequestTransactionManager.go                   |  12 +-
 .../RequestTransactionManager_test.go              |   4 +-
 .../spi/transactions/mock_CompletionFuture_test.go | 132 +++++++++++++++++++++
 .../mock_RequestTransactionManagerOption_test.go   |   2 +-
 .../mock_RequestTransactionManager_test.go         |   2 +-
 .../mock_RequestTransactionRunnable_test.go        |  16 +--
 .../mock_RequestTransaction_test.go                |   2 +-
 plc4go/spi/transactions/mock_requirements.go       |  31 +++++
 8 files changed, 182 insertions(+), 19 deletions(-)

diff --git a/plc4go/spi/RequestTransactionManager.go b/plc4go/spi/transactions/RequestTransactionManager.go
similarity index 97%
rename from plc4go/spi/RequestTransactionManager.go
rename to plc4go/spi/transactions/RequestTransactionManager.go
index cf14625ad6..08865904b1 100644
--- a/plc4go/spi/RequestTransactionManager.go
+++ b/plc4go/spi/transactions/RequestTransactionManager.go
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package spi
+package transactions
 
 import (
 	"container/list"
@@ -42,7 +42,7 @@ func init() {
 	sharedExecutorInstance.Start()
 }
 
-type RequestTransactionRunnable func(transaction RequestTransaction)
+type RequestTransactionRunnable func(RequestTransaction)
 
 // RequestTransaction represents a transaction
 type RequestTransaction interface {
@@ -107,7 +107,7 @@ type requestTransaction struct {
 
 type requestTransactionManager struct {
 	runningRequests []*requestTransaction
-	// How many Transactions are allowed to run at the same time?
+	// How many transactions are allowed to run at the same time?
 	numberOfConcurrentRequests int
 	// Assigns each request a Unique Transaction Id, especially important for failure handling
 	transactionId    int32
@@ -139,12 +139,12 @@ func (r *requestTransactionManager) SetNumberOfConcurrentRequests(numberOfConcur
 }
 
 func (r *requestTransactionManager) submitTransaction(transaction *requestTransaction) {
-	// Add this Request with this transaction i the Worklog
-	// Put Transaction into Worklog
+	// Add this Request with the transaction i the work log
+	// Put Transaction into work log
 	r.workLogMutex.Lock()
 	r.workLog.PushFront(transaction)
 	r.workLogMutex.Unlock()
-	// Try to Process the Worklog
+	// Try to Process the work log
 	r.processWorklog()
 }
 
diff --git a/plc4go/spi/RequestTransactionManager_test.go b/plc4go/spi/transactions/RequestTransactionManager_test.go
similarity index 99%
rename from plc4go/spi/RequestTransactionManager_test.go
rename to plc4go/spi/transactions/RequestTransactionManager_test.go
index 9c364221d1..c46767ece0 100644
--- a/plc4go/spi/RequestTransactionManager_test.go
+++ b/plc4go/spi/transactions/RequestTransactionManager_test.go
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package spi
+package transactions
 
 import (
 	"container/list"
@@ -443,7 +443,7 @@ func Test_requestTransaction_AwaitCompletion(t1 *testing.T) {
 							r := &requestTransaction{}
 							go func() {
 								time.Sleep(100 * time.Millisecond)
-								// We fake a ending transaction like that
+								// We fake an ending transaction like that
 								r.transactionId = 1
 							}()
 							return r
diff --git a/plc4go/spi/transactions/mock_CompletionFuture_test.go b/plc4go/spi/transactions/mock_CompletionFuture_test.go
new file mode 100644
index 0000000000..ec72fc9d8a
--- /dev/null
+++ b/plc4go/spi/transactions/mock_CompletionFuture_test.go
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by mockery v2.28.1. DO NOT EDIT.
+
+package transactions
+
+import (
+	context "context"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// MockCompletionFuture is an autogenerated mock type for the CompletionFuture type
+type MockCompletionFuture struct {
+	mock.Mock
+}
+
+type MockCompletionFuture_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockCompletionFuture) EXPECT() *MockCompletionFuture_Expecter {
+	return &MockCompletionFuture_Expecter{mock: &_m.Mock}
+}
+
+// AwaitCompletion provides a mock function with given fields: ctx
+func (_m *MockCompletionFuture) AwaitCompletion(ctx context.Context) error {
+	ret := _m.Called(ctx)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+		r0 = rf(ctx)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// MockCompletionFuture_AwaitCompletion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AwaitCompletion'
+type MockCompletionFuture_AwaitCompletion_Call struct {
+	*mock.Call
+}
+
+// AwaitCompletion is a helper method to define mock.On call
+//   - ctx context.Context
+func (_e *MockCompletionFuture_Expecter) AwaitCompletion(ctx interface{}) *MockCompletionFuture_AwaitCompletion_Call {
+	return &MockCompletionFuture_AwaitCompletion_Call{Call: _e.mock.On("AwaitCompletion", ctx)}
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) Run(run func(ctx context.Context)) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context))
+	})
+	return _c
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) Return(_a0 error) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockCompletionFuture_AwaitCompletion_Call) RunAndReturn(run func(context.Context) error) *MockCompletionFuture_AwaitCompletion_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Cancel provides a mock function with given fields: interrupt, err
+func (_m *MockCompletionFuture) Cancel(interrupt bool, err error) {
+	_m.Called(interrupt, err)
+}
+
+// MockCompletionFuture_Cancel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cancel'
+type MockCompletionFuture_Cancel_Call struct {
+	*mock.Call
+}
+
+// Cancel is a helper method to define mock.On call
+//   - interrupt bool
+//   - err error
+func (_e *MockCompletionFuture_Expecter) Cancel(interrupt interface{}, err interface{}) *MockCompletionFuture_Cancel_Call {
+	return &MockCompletionFuture_Cancel_Call{Call: _e.mock.On("Cancel", interrupt, err)}
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) Run(run func(interrupt bool, err error)) *MockCompletionFuture_Cancel_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(bool), args[1].(error))
+	})
+	return _c
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) Return() *MockCompletionFuture_Cancel_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockCompletionFuture_Cancel_Call) RunAndReturn(run func(bool, error)) *MockCompletionFuture_Cancel_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockCompletionFuture interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockCompletionFuture creates a new instance of MockCompletionFuture. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockCompletionFuture(t mockConstructorTestingTNewMockCompletionFuture) *MockCompletionFuture {
+	mock := &MockCompletionFuture{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/mock_RequestTransactionManagerOption_test.go b/plc4go/spi/transactions/mock_RequestTransactionManagerOption_test.go
similarity index 99%
rename from plc4go/spi/mock_RequestTransactionManagerOption_test.go
rename to plc4go/spi/transactions/mock_RequestTransactionManagerOption_test.go
index 59a3f73e36..8bea8076f2 100644
--- a/plc4go/spi/mock_RequestTransactionManagerOption_test.go
+++ b/plc4go/spi/transactions/mock_RequestTransactionManagerOption_test.go
@@ -19,7 +19,7 @@
 
 // Code generated by mockery v2.28.1. DO NOT EDIT.
 
-package spi
+package transactions
 
 import mock "github.com/stretchr/testify/mock"
 
diff --git a/plc4go/spi/mock_RequestTransactionManager_test.go b/plc4go/spi/transactions/mock_RequestTransactionManager_test.go
similarity index 99%
rename from plc4go/spi/mock_RequestTransactionManager_test.go
rename to plc4go/spi/transactions/mock_RequestTransactionManager_test.go
index 962439f3fa..f15b138ff3 100644
--- a/plc4go/spi/mock_RequestTransactionManager_test.go
+++ b/plc4go/spi/transactions/mock_RequestTransactionManager_test.go
@@ -19,7 +19,7 @@
 
 // Code generated by mockery v2.28.1. DO NOT EDIT.
 
-package spi
+package transactions
 
 import mock "github.com/stretchr/testify/mock"
 
diff --git a/plc4go/spi/mock_RequestTransactionRunnable_test.go b/plc4go/spi/transactions/mock_RequestTransactionRunnable_test.go
similarity index 85%
rename from plc4go/spi/mock_RequestTransactionRunnable_test.go
rename to plc4go/spi/transactions/mock_RequestTransactionRunnable_test.go
index b621d0cb8e..e80caf3a71 100644
--- a/plc4go/spi/mock_RequestTransactionRunnable_test.go
+++ b/plc4go/spi/transactions/mock_RequestTransactionRunnable_test.go
@@ -19,7 +19,7 @@
 
 // Code generated by mockery v2.28.1. DO NOT EDIT.
 
-package spi
+package transactions
 
 import mock "github.com/stretchr/testify/mock"
 
@@ -36,9 +36,9 @@ func (_m *MockRequestTransactionRunnable) EXPECT() *MockRequestTransactionRunnab
 	return &MockRequestTransactionRunnable_Expecter{mock: &_m.Mock}
 }
 
-// Execute provides a mock function with given fields: transaction
-func (_m *MockRequestTransactionRunnable) Execute(transaction RequestTransaction) {
-	_m.Called(transaction)
+// Execute provides a mock function with given fields: _a0
+func (_m *MockRequestTransactionRunnable) Execute(_a0 RequestTransaction) {
+	_m.Called(_a0)
 }
 
 // MockRequestTransactionRunnable_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute'
@@ -47,12 +47,12 @@ type MockRequestTransactionRunnable_Execute_Call struct {
 }
 
 // Execute is a helper method to define mock.On call
-//   - transaction RequestTransaction
-func (_e *MockRequestTransactionRunnable_Expecter) Execute(transaction interface{}) *MockRequestTransactionRunnable_Execute_Call {
-	return &MockRequestTransactionRunnable_Execute_Call{Call: _e.mock.On("Execute", transaction)}
+//   - _a0 RequestTransaction
+func (_e *MockRequestTransactionRunnable_Expecter) Execute(_a0 interface{}) *MockRequestTransactionRunnable_Execute_Call {
+	return &MockRequestTransactionRunnable_Execute_Call{Call: _e.mock.On("Execute", _a0)}
 }
 
-func (_c *MockRequestTransactionRunnable_Execute_Call) Run(run func(transaction RequestTransaction)) *MockRequestTransactionRunnable_Execute_Call {
+func (_c *MockRequestTransactionRunnable_Execute_Call) Run(run func(_a0 RequestTransaction)) *MockRequestTransactionRunnable_Execute_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(RequestTransaction))
 	})
diff --git a/plc4go/spi/mock_RequestTransaction_test.go b/plc4go/spi/transactions/mock_RequestTransaction_test.go
similarity index 99%
rename from plc4go/spi/mock_RequestTransaction_test.go
rename to plc4go/spi/transactions/mock_RequestTransaction_test.go
index 18ed7f3aa9..2c8e24ec20 100644
--- a/plc4go/spi/mock_RequestTransaction_test.go
+++ b/plc4go/spi/transactions/mock_RequestTransaction_test.go
@@ -19,7 +19,7 @@
 
 // Code generated by mockery v2.28.1. DO NOT EDIT.
 
-package spi
+package transactions
 
 import (
 	context "context"
diff --git a/plc4go/spi/transactions/mock_requirements.go b/plc4go/spi/transactions/mock_requirements.go
new file mode 100644
index 0000000000..4feb95b8de
--- /dev/null
+++ b/plc4go/spi/transactions/mock_requirements.go
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package transactions
+
+import (
+	"github.com/apache/plc4x/plc4go/spi/utils"
+)
+
+// Note this file is a Helper for mockery to generate use mocks from other package
+
+// Deprecated: don't use it in productive code
+type CompletionFuture interface {
+	utils.CompletionFuture
+}


[plc4x] 02/03: refactor(plc4go/spi): move WorkerPool to own package

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit c4bf3ebd6206d470ab570c4d67710b95fe153c42
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 31 14:49:15 2023 +0200

    refactor(plc4go/spi): move WorkerPool to own package
---
 plc4go/spi/{utils => pool}/WorkerPool.go      |  82 ++++++----
 plc4go/spi/{utils => pool}/WorkerPool_test.go |  55 ++++---
 plc4go/spi/utils/mock_ExecutorOption_test.go  |  85 -----------
 plc4go/spi/utils/mock_Executor_test.go        | 207 --------------------------
 4 files changed, 82 insertions(+), 347 deletions(-)

diff --git a/plc4go/spi/utils/WorkerPool.go b/plc4go/spi/pool/WorkerPool.go
similarity index 80%
rename from plc4go/spi/utils/WorkerPool.go
rename to plc4go/spi/pool/WorkerPool.go
index a1d8202a7c..ae1f59849f 100644
--- a/plc4go/spi/utils/WorkerPool.go
+++ b/plc4go/spi/pool/WorkerPool.go
@@ -17,14 +17,16 @@
  * under the License.
  */
 
-package utils
+package pool
 
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog/log"
+	"io"
 	"runtime/debug"
 	"sync"
 	"sync/atomic"
@@ -41,6 +43,8 @@ type worker struct {
 	executor     *executor
 	hasEnded     atomic.Bool
 	lastReceived time.Time
+
+	log zerolog.Logger
 }
 
 func (w *worker) initialize() {
@@ -54,7 +58,7 @@ func (w *worker) initialize() {
 func (w *worker) work() {
 	defer func() {
 		if recovered := recover(); recovered != nil {
-			log.Error().Msgf("Recovering from panic():%v. Stack: %s", recovered, debug.Stack())
+			w.log.Error().Msgf("Recovering from panic():%v. Stack: %s", recovered, debug.Stack())
 		}
 		if !w.shutdown.Load() {
 			// if we are not in shutdown we continue
@@ -72,7 +76,7 @@ func (w *worker) work() {
 	for !w.shutdown.Load() {
 		workerLog.Debug().Msg("Working")
 		select {
-		case _workItem := <-w.executor.queue:
+		case _workItem := <-w.executor.workItems:
 			w.lastReceived = time.Now()
 			workerLog.Debug().Msgf("Got work item %v", _workItem)
 			if _workItem.completionFuture.cancelRequested.Load() || (w.shutdown.Load() && w.interrupted.Load()) {
@@ -103,6 +107,7 @@ func (w *workItem) String() string {
 }
 
 type Executor interface {
+	io.Closer
 	Start()
 	Stop()
 	Submit(ctx context.Context, workItemId int32, runnable Runnable) CompletionFuture
@@ -115,24 +120,32 @@ type executor struct {
 	shutdown           bool
 	stateChange        sync.Mutex
 	worker             []*worker
-	queue              chan workItem
+	workItems          chan workItem
 	traceWorkers       bool
+
+	log zerolog.Logger
 }
 
-func NewFixedSizeExecutor(numberOfWorkers, queueDepth int, options ...ExecutorOption) Executor {
+func NewFixedSizeExecutor(numberOfWorkers, queueDepth int, _options ...options.WithOption) Executor {
 	workers := make([]*worker, numberOfWorkers)
+	customLogger := options.ExtractCustomLogger(_options...)
 	for i := 0; i < numberOfWorkers; i++ {
 		workers[i] = &worker{
-			id: i,
+			id:  i,
+			log: customLogger,
 		}
 	}
 	_executor := &executor{
 		maxNumberOfWorkers: numberOfWorkers,
-		queue:              make(chan workItem, queueDepth),
+		workItems:          make(chan workItem, queueDepth),
 		worker:             workers,
+		log:                customLogger,
 	}
-	for _, option := range options {
-		option(_executor)
+	for _, option := range _options {
+		switch option := option.(type) {
+		case *tracerWorkersOption:
+			_executor.traceWorkers = option.traceWorkers
+		}
 	}
 	for i := 0; i < numberOfWorkers; i++ {
 		workers[i].executor = _executor
@@ -144,14 +157,19 @@ var upScaleInterval = 100 * time.Millisecond
 var downScaleInterval = 5 * time.Second
 var timeToBecomeUnused = 5 * time.Second
 
-func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorOption) Executor {
+func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, _options ...options.WithOption) Executor {
+	customLogger := options.ExtractCustomLogger(_options...)
 	_executor := &executor{
 		maxNumberOfWorkers: maxNumberOfWorkers,
-		queue:              make(chan workItem, queueDepth),
+		workItems:          make(chan workItem, queueDepth),
 		worker:             make([]*worker, 0),
+		log:                customLogger,
 	}
-	for _, option := range options {
-		option(_executor)
+	for _, option := range _options {
+		switch option := option.(type) {
+		case *tracerWorkersOption:
+			_executor.traceWorkers = option.traceWorkers
+		}
 	}
 	// We spawn one initial worker
 	_executor.worker = append(_executor.worker, &worker{
@@ -159,13 +177,14 @@ func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorO
 		interrupter:  make(chan struct{}, 1),
 		executor:     _executor,
 		lastReceived: time.Now(),
+		log:          customLogger,
 	})
 	mutex := sync.Mutex{}
 	// Worker spawner
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				customLogger.Error().Msgf("panic-ed %v", err)
 			}
 		}()
 		workerLog := log.With().Str("Worker type", "spawner").Logger()
@@ -176,7 +195,7 @@ func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorO
 			workerLog.Debug().Msgf("Sleeping for %v", upScaleInterval)
 			time.Sleep(upScaleInterval)
 			mutex.Lock()
-			numberOfItemsInQueue := len(_executor.queue)
+			numberOfItemsInQueue := len(_executor.workItems)
 			numberOfWorkers := len(_executor.worker)
 			workerLog.Debug().Msgf("Checking if %d > %d && %d < %d", numberOfItemsInQueue, numberOfWorkers, numberOfWorkers, maxNumberOfWorkers)
 			if numberOfItemsInQueue > numberOfWorkers && numberOfWorkers < maxNumberOfWorkers {
@@ -185,6 +204,7 @@ func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorO
 					interrupter:  make(chan struct{}, 1),
 					executor:     _executor,
 					lastReceived: time.Now(),
+					log:          customLogger,
 				}
 				_executor.worker = append(_executor.worker, _worker)
 				_worker.initialize()
@@ -200,7 +220,7 @@ func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorO
 	go func() {
 		defer func() {
 			if err := recover(); err != nil {
-				log.Error().Msgf("panic-ed %v", err)
+				_executor.log.Error().Msgf("panic-ed %v", err)
 			}
 		}()
 		workerLog := log.With().Str("Worker type", "killer").Logger()
@@ -231,12 +251,13 @@ func NewDynamicExecutor(maxNumberOfWorkers, queueDepth int, options ...ExecutorO
 	return _executor
 }
 
-type ExecutorOption func(*executor)
+func WithExecutorOptionTracerWorkers(traceWorkers bool) options.WithOption {
+	return &tracerWorkersOption{traceWorkers: traceWorkers}
+}
 
-func WithExecutorOptionTracerWorkers(traceWorkers bool) ExecutorOption {
-	return func(executor *executor) {
-		executor.traceWorkers = traceWorkers
-	}
+type tracerWorkersOption struct {
+	options.Option
+	traceWorkers bool
 }
 
 func (e *executor) Submit(ctx context.Context, workItemId int32, runnable Runnable) CompletionFuture {
@@ -245,20 +266,24 @@ func (e *executor) Submit(ctx context.Context, workItemId int32, runnable Runnab
 		value.Store(errors.New("runnable must not be nil"))
 		return &future{err: value}
 	}
-	log.Trace().Int32("workItemId", workItemId).Msg("Submitting runnable")
+	e.log.Trace().Int32("workItemId", workItemId).Msg("Submitting runnable")
 	completionFuture := &future{}
+	if e.shutdown {
+		completionFuture.Cancel(false, errors.New("executor in shutdown"))
+		return completionFuture
+	}
 	select {
-	case e.queue <- workItem{
+	case e.workItems <- workItem{
 		workItemId:       workItemId,
 		runnable:         runnable,
 		completionFuture: completionFuture,
 	}:
-		log.Trace().Msg("Item added")
+		e.log.Trace().Msg("Item added")
 	case <-ctx.Done():
 		completionFuture.Cancel(false, ctx.Err())
 	}
 
-	log.Trace().Int32("workItemId", workItemId).Msg("runnable queued")
+	e.log.Trace().Int32("workItemId", workItemId).Msg("runnable queued")
 	return completionFuture
 }
 
@@ -284,17 +309,22 @@ func (e *executor) Stop() {
 		return
 	}
 	e.shutdown = true
-	close(e.queue)
 	for i := 0; i < len(e.worker); i++ {
 		worker := e.worker[i]
 		worker.shutdown.Store(true)
 		worker.interrupted.Store(true)
 		close(worker.interrupter)
 	}
+	close(e.workItems)
 	e.running = false
 	e.shutdown = false
 }
 
+func (e *executor) Close() error {
+	e.Stop()
+	return nil
+}
+
 func (e *executor) IsRunning() bool {
 	return e.running && !e.shutdown
 }
diff --git a/plc4go/spi/utils/WorkerPool_test.go b/plc4go/spi/pool/WorkerPool_test.go
similarity index 93%
rename from plc4go/spi/utils/WorkerPool_test.go
rename to plc4go/spi/pool/WorkerPool_test.go
index fcb006b982..d940b1c545 100644
--- a/plc4go/spi/utils/WorkerPool_test.go
+++ b/plc4go/spi/pool/WorkerPool_test.go
@@ -17,11 +17,12 @@
  * under the License.
  */
 
-package utils
+package pool
 
 import (
 	"context"
 	"fmt"
+	"github.com/apache/plc4x/plc4go/spi/options"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"math/rand"
@@ -68,7 +69,7 @@ func TestExecutor_Start(t *testing.T) {
 				running:      tt.fields.running,
 				shutdown:     tt.fields.shutdown,
 				worker:       tt.fields.worker,
-				queue:        tt.fields.queue,
+				workItems:    tt.fields.queue,
 				traceWorkers: tt.fields.traceWorkers,
 			}
 			e.Start()
@@ -116,7 +117,7 @@ func TestExecutor_Stop(t *testing.T) {
 				running:      tt.fields.running,
 				shutdown:     tt.fields.shutdown,
 				worker:       tt.fields.worker,
-				queue:        tt.fields.queue,
+				workItems:    tt.fields.queue,
 				traceWorkers: tt.fields.traceWorkers,
 			}
 			e.Stop()
@@ -198,7 +199,7 @@ func TestExecutor_Submit(t *testing.T) {
 					running:      executor.running,
 					shutdown:     executor.shutdown,
 					worker:       executor.worker,
-					queue:        executor.queue,
+					queue:        executor.workItems,
 					traceWorkers: true,
 				}
 			}(),
@@ -222,7 +223,7 @@ func TestExecutor_Submit(t *testing.T) {
 				running:      tt.fields.running,
 				shutdown:     tt.fields.shutdown,
 				worker:       tt.fields.worker,
-				queue:        tt.fields.queue,
+				workItems:    tt.fields.queue,
 				traceWorkers: tt.fields.traceWorkers,
 			}
 			e.Start()
@@ -239,7 +240,7 @@ func TestNewFixedSizeExecutor(t *testing.T) {
 	type args struct {
 		numberOfWorkers int
 		queueDepth      int
-		options         []ExecutorOption
+		options         []options.WithOption
 	}
 	tests := []struct {
 		name              string
@@ -251,10 +252,10 @@ func TestNewFixedSizeExecutor(t *testing.T) {
 			args: args{
 				numberOfWorkers: 13,
 				queueDepth:      14,
-				options:         []ExecutorOption{WithExecutorOptionTracerWorkers(true)},
+				options:         []options.WithOption{WithExecutorOptionTracerWorkers(true)},
 			},
 			executorValidator: func(t *testing.T, e *executor) bool {
-				return !e.running && !e.shutdown && len(e.worker) == 13 && cap(e.queue) == 14
+				return !e.running && !e.shutdown && len(e.worker) == 13 && cap(e.workItems) == 14
 			},
 		},
 	}
@@ -271,7 +272,7 @@ func TestNewDynamicExecutor(t *testing.T) {
 	type args struct {
 		numberOfWorkers int
 		queueDepth      int
-		options         []ExecutorOption
+		options         []options.WithOption
 	}
 	tests := []struct {
 		name              string
@@ -284,13 +285,13 @@ func TestNewDynamicExecutor(t *testing.T) {
 			args: args{
 				numberOfWorkers: 13,
 				queueDepth:      14,
-				options:         []ExecutorOption{WithExecutorOptionTracerWorkers(true)},
+				options:         []options.WithOption{WithExecutorOptionTracerWorkers(true)},
 			},
 			executorValidator: func(t *testing.T, e *executor) bool {
 				assert.False(t, e.running)
 				assert.False(t, e.shutdown)
 				assert.Len(t, e.worker, 1)
-				assert.Equal(t, cap(e.queue), 14)
+				assert.Equal(t, cap(e.workItems), 14)
 				return true
 			},
 		},
@@ -299,7 +300,7 @@ func TestNewDynamicExecutor(t *testing.T) {
 			args: args{
 				numberOfWorkers: 2,
 				queueDepth:      2,
-				options:         []ExecutorOption{WithExecutorOptionTracerWorkers(true)},
+				options:         []options.WithOption{WithExecutorOptionTracerWorkers(true)},
 			},
 			manipulator: func(t *testing.T, e *executor) {
 				{
@@ -331,7 +332,7 @@ func TestNewDynamicExecutor(t *testing.T) {
 				t.Log("fill some jobs")
 				go func() {
 					for i := 0; i < 500; i++ {
-						e.queue <- workItem{
+						e.workItems <- workItem{
 							workItemId: int32(i),
 							runnable: func() {
 								max := 100
@@ -372,21 +373,17 @@ func TestWithExecutorOptionTracerWorkers(t *testing.T) {
 	tests := []struct {
 		name              string
 		args              args
-		executorValidator func(*testing.T, *executor) bool
+		executorValidator options.WithOption
 	}{
 		{
-			name: "option should set option",
-			args: args{traceWorkers: true},
-			executorValidator: func(t *testing.T, e *executor) bool {
-				return e.traceWorkers == true
-			},
+			name:              "option should set option",
+			args:              args{traceWorkers: true},
+			executorValidator: &tracerWorkersOption{traceWorkers: true},
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			var _executor executor
-			WithExecutorOptionTracerWorkers(tt.args.traceWorkers)(&_executor)
-			assert.True(t, tt.executorValidator(t, &_executor))
+			assert.Equal(t, tt.executorValidator, WithExecutorOptionTracerWorkers(tt.args.traceWorkers))
 		})
 	}
 }
@@ -440,11 +437,11 @@ func TestWorker_work(t *testing.T) {
 				id: 0,
 				executor: func() *executor {
 					e := &executor{
-						queue:        make(chan workItem),
+						workItems:    make(chan workItem),
 						traceWorkers: true,
 					}
 					go func() {
-						e.queue <- workItem{
+						e.workItems <- workItem{
 							workItemId: 0,
 							runnable: func() {
 								panic("Oh no what should I do???")
@@ -474,11 +471,11 @@ func TestWorker_work(t *testing.T) {
 				id: 1,
 				executor: func() *executor {
 					e := &executor{
-						queue:        make(chan workItem),
+						workItems:    make(chan workItem),
 						traceWorkers: true,
 					}
 					go func() {
-						e.queue <- workItem{
+						e.workItems <- workItem{
 							workItemId: 0,
 							runnable: func() {
 								time.Sleep(time.Millisecond * 70)
@@ -507,7 +504,7 @@ func TestWorker_work(t *testing.T) {
 				id: 1,
 				executor: func() *executor {
 					e := &executor{
-						queue:        make(chan workItem),
+						workItems:    make(chan workItem),
 						traceWorkers: true,
 					}
 					return e
@@ -532,13 +529,13 @@ func TestWorker_work(t *testing.T) {
 				id: 1,
 				executor: func() *executor {
 					e := &executor{
-						queue:        make(chan workItem),
+						workItems:    make(chan workItem),
 						traceWorkers: true,
 					}
 					go func() {
 						completionFuture := &future{}
 						completionFuture.cancelRequested.Store(true)
-						e.queue <- workItem{
+						e.workItems <- workItem{
 							workItemId: 0,
 							runnable: func() {
 								time.Sleep(time.Millisecond * 70)
diff --git a/plc4go/spi/utils/mock_ExecutorOption_test.go b/plc4go/spi/utils/mock_ExecutorOption_test.go
deleted file mode 100644
index 9d0a05afa5..0000000000
--- a/plc4go/spi/utils/mock_ExecutorOption_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// Code generated by mockery v2.28.1. DO NOT EDIT.
-
-package utils
-
-import mock "github.com/stretchr/testify/mock"
-
-// MockExecutorOption is an autogenerated mock type for the ExecutorOption type
-type MockExecutorOption struct {
-	mock.Mock
-}
-
-type MockExecutorOption_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *MockExecutorOption) EXPECT() *MockExecutorOption_Expecter {
-	return &MockExecutorOption_Expecter{mock: &_m.Mock}
-}
-
-// Execute provides a mock function with given fields: _a0
-func (_m *MockExecutorOption) Execute(_a0 *executor) {
-	_m.Called(_a0)
-}
-
-// MockExecutorOption_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute'
-type MockExecutorOption_Execute_Call struct {
-	*mock.Call
-}
-
-// Execute is a helper method to define mock.On call
-//   - _a0 *executor
-func (_e *MockExecutorOption_Expecter) Execute(_a0 interface{}) *MockExecutorOption_Execute_Call {
-	return &MockExecutorOption_Execute_Call{Call: _e.mock.On("Execute", _a0)}
-}
-
-func (_c *MockExecutorOption_Execute_Call) Run(run func(_a0 *executor)) *MockExecutorOption_Execute_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(*executor))
-	})
-	return _c
-}
-
-func (_c *MockExecutorOption_Execute_Call) Return() *MockExecutorOption_Execute_Call {
-	_c.Call.Return()
-	return _c
-}
-
-func (_c *MockExecutorOption_Execute_Call) RunAndReturn(run func(*executor)) *MockExecutorOption_Execute_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-type mockConstructorTestingTNewMockExecutorOption interface {
-	mock.TestingT
-	Cleanup(func())
-}
-
-// NewMockExecutorOption creates a new instance of MockExecutorOption. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewMockExecutorOption(t mockConstructorTestingTNewMockExecutorOption) *MockExecutorOption {
-	mock := &MockExecutorOption{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}
diff --git a/plc4go/spi/utils/mock_Executor_test.go b/plc4go/spi/utils/mock_Executor_test.go
deleted file mode 100644
index fa86fa9cf4..0000000000
--- a/plc4go/spi/utils/mock_Executor_test.go
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// Code generated by mockery v2.28.1. DO NOT EDIT.
-
-package utils
-
-import (
-	context "context"
-
-	mock "github.com/stretchr/testify/mock"
-)
-
-// MockExecutor is an autogenerated mock type for the Executor type
-type MockExecutor struct {
-	mock.Mock
-}
-
-type MockExecutor_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *MockExecutor) EXPECT() *MockExecutor_Expecter {
-	return &MockExecutor_Expecter{mock: &_m.Mock}
-}
-
-// IsRunning provides a mock function with given fields:
-func (_m *MockExecutor) IsRunning() bool {
-	ret := _m.Called()
-
-	var r0 bool
-	if rf, ok := ret.Get(0).(func() bool); ok {
-		r0 = rf()
-	} else {
-		r0 = ret.Get(0).(bool)
-	}
-
-	return r0
-}
-
-// MockExecutor_IsRunning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsRunning'
-type MockExecutor_IsRunning_Call struct {
-	*mock.Call
-}
-
-// IsRunning is a helper method to define mock.On call
-func (_e *MockExecutor_Expecter) IsRunning() *MockExecutor_IsRunning_Call {
-	return &MockExecutor_IsRunning_Call{Call: _e.mock.On("IsRunning")}
-}
-
-func (_c *MockExecutor_IsRunning_Call) Run(run func()) *MockExecutor_IsRunning_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run()
-	})
-	return _c
-}
-
-func (_c *MockExecutor_IsRunning_Call) Return(_a0 bool) *MockExecutor_IsRunning_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *MockExecutor_IsRunning_Call) RunAndReturn(run func() bool) *MockExecutor_IsRunning_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// Start provides a mock function with given fields:
-func (_m *MockExecutor) Start() {
-	_m.Called()
-}
-
-// MockExecutor_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
-type MockExecutor_Start_Call struct {
-	*mock.Call
-}
-
-// Start is a helper method to define mock.On call
-func (_e *MockExecutor_Expecter) Start() *MockExecutor_Start_Call {
-	return &MockExecutor_Start_Call{Call: _e.mock.On("Start")}
-}
-
-func (_c *MockExecutor_Start_Call) Run(run func()) *MockExecutor_Start_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run()
-	})
-	return _c
-}
-
-func (_c *MockExecutor_Start_Call) Return() *MockExecutor_Start_Call {
-	_c.Call.Return()
-	return _c
-}
-
-func (_c *MockExecutor_Start_Call) RunAndReturn(run func()) *MockExecutor_Start_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// Stop provides a mock function with given fields:
-func (_m *MockExecutor) Stop() {
-	_m.Called()
-}
-
-// MockExecutor_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
-type MockExecutor_Stop_Call struct {
-	*mock.Call
-}
-
-// Stop is a helper method to define mock.On call
-func (_e *MockExecutor_Expecter) Stop() *MockExecutor_Stop_Call {
-	return &MockExecutor_Stop_Call{Call: _e.mock.On("Stop")}
-}
-
-func (_c *MockExecutor_Stop_Call) Run(run func()) *MockExecutor_Stop_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run()
-	})
-	return _c
-}
-
-func (_c *MockExecutor_Stop_Call) Return() *MockExecutor_Stop_Call {
-	_c.Call.Return()
-	return _c
-}
-
-func (_c *MockExecutor_Stop_Call) RunAndReturn(run func()) *MockExecutor_Stop_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// Submit provides a mock function with given fields: ctx, workItemId, runnable
-func (_m *MockExecutor) Submit(ctx context.Context, workItemId int32, runnable Runnable) CompletionFuture {
-	ret := _m.Called(ctx, workItemId, runnable)
-
-	var r0 CompletionFuture
-	if rf, ok := ret.Get(0).(func(context.Context, int32, Runnable) CompletionFuture); ok {
-		r0 = rf(ctx, workItemId, runnable)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(CompletionFuture)
-		}
-	}
-
-	return r0
-}
-
-// MockExecutor_Submit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Submit'
-type MockExecutor_Submit_Call struct {
-	*mock.Call
-}
-
-// Submit is a helper method to define mock.On call
-//   - ctx context.Context
-//   - workItemId int32
-//   - runnable Runnable
-func (_e *MockExecutor_Expecter) Submit(ctx interface{}, workItemId interface{}, runnable interface{}) *MockExecutor_Submit_Call {
-	return &MockExecutor_Submit_Call{Call: _e.mock.On("Submit", ctx, workItemId, runnable)}
-}
-
-func (_c *MockExecutor_Submit_Call) Run(run func(ctx context.Context, workItemId int32, runnable Runnable)) *MockExecutor_Submit_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(int32), args[2].(Runnable))
-	})
-	return _c
-}
-
-func (_c *MockExecutor_Submit_Call) Return(_a0 CompletionFuture) *MockExecutor_Submit_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *MockExecutor_Submit_Call) RunAndReturn(run func(context.Context, int32, Runnable) CompletionFuture) *MockExecutor_Submit_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-type mockConstructorTestingTNewMockExecutor interface {
-	mock.TestingT
-	Cleanup(func())
-}
-
-// NewMockExecutor creates a new instance of MockExecutor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewMockExecutor(t mockConstructorTestingTNewMockExecutor) *MockExecutor {
-	mock := &MockExecutor{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}