/// <summary>
        /// Consumes a message on a daemon thread using a blocking receive call
        /// (traced with the <see cref="IIncomingMessageReceiveTracer"/> and <see cref="IIncomingMessageProcessTracer"/>)
        /// The Dynatrace tag is transported along with the message
        /// </summary>
        public static void ConsumerDaemonExample()
        {
            string serverEndpoint = "messageserver.example.com:1234";
            string topic          = "my-topic";
            IMessagingSystemInfo messagingSystemInfo = SampleApplication.OneAgentSdk
                                                       .CreateMessagingSystemInfo(MessageSystemVendor.KAFKA, topic, MessageDestinationType.TOPIC, ChannelType.TCP_IP, serverEndpoint);

            IIncomingMessageReceiveTracer receiveTracer = SampleApplication.OneAgentSdk.TraceIncomingMessageReceive(messagingSystemInfo);

            receiveTracer.Start();
            try
            {
                // blocking call until message is available:
                ReceiveResult receiveResult = MyMessagingSystem.ReceiveMessage();
                Message       message       = receiveResult.Message;

                IIncomingMessageProcessTracer processTracer = SampleApplication.OneAgentSdk.TraceIncomingMessageProcess(messagingSystemInfo);

                // retrieve Dynatrace tag created using the outgoing message tracer to link both sides together:
                if (message.Headers.ContainsKey(OneAgentSdkConstants.DYNATRACE_MESSAGE_PROPERTYNAME))
                {
                    processTracer.SetDynatraceByteTag(message.Headers[OneAgentSdkConstants.DYNATRACE_MESSAGE_PROPERTYNAME]);
                }

                // start processing:
                processTracer.Start();
                processTracer.SetCorrelationId(message.CorrelationId);           // optional
                processTracer.SetVendorMessageId(receiveResult.VendorMessageId); // optional
                try
                {
                    ProcessMessage(message); // do the work ...
                }
                catch (Exception e)
                {
                    processTracer.Error(e);
                    // handle or rethrow
                    throw e;
                }
                finally
                {
                    processTracer.End();
                }
            }
            catch (Exception e)
            {
                receiveTracer.Error(e);
                // handle or rethrow
                throw e;
            }
            finally
            {
                receiveTracer.End();
            }
        }
        /// <summary>
        /// Produces a message (traced with the <see cref="IOutgoingMessageTracer"/>) and consumes it
        /// (traced with the <see cref="IIncomingMessageReceiveTracer"/> and <see cref="IIncomingMessageProcessTracer"/>)
        /// The Dynatrace tag is transported along with the message
        /// </summary>
        public static void ProducerConsumerExample()
        {
            string serverEndpoint = "messageserver.example.com:1234";
            string topic          = "my-topic";
            IMessagingSystemInfo messagingSystemInfo = SampleApplication.OneAgentSdk
                                                       .CreateMessagingSystemInfo(MessageSystemVendor.KAFKA, topic, MessageDestinationType.TOPIC, ChannelType.TCP_IP, serverEndpoint);

            IOutgoingMessageTracer outgoingTracer = SampleApplication.OneAgentSdk.TraceOutgoingMessage(messagingSystemInfo);

            outgoingTracer.Start();
            try
            {
                Message message = new Message
                {
                    CorrelationId = "my-correlation-id-1234" // optional, determined by application
                };

                // transport the Dynatrace tag along with the message to allow the outgoing message tracer to be linked
                // together with the message processing tracer on the receiving side
                message.Headers[OneAgentSdkConstants.DYNATRACE_MESSAGE_PROPERTYNAME] = outgoingTracer.GetDynatraceByteTag();

                SendResult result = MyMessagingSystem.SendMessage(message);

                outgoingTracer.SetCorrelationId(message.CorrelationId);    // optional
                outgoingTracer.SetVendorMessageId(result.VendorMessageId); // optional
            }
            catch (Exception e)
            {
                outgoingTracer.Error(e);
                // handle or rethrow
                throw e;
            }
            finally
            {
                outgoingTracer.End();
            }

            // represents server side processing
            Thread server = new Thread(() =>
            {
                IIncomingMessageReceiveTracer receiveTracer = SampleApplication.OneAgentSdk.TraceIncomingMessageReceive(messagingSystemInfo);

                receiveTracer.Start();
                try
                {
                    // blocking call until message is available:
                    ReceiveResult receiveResult = MyMessagingSystem.ReceiveMessage();
                    Message message             = receiveResult.Message;

                    IIncomingMessageProcessTracer processTracer = SampleApplication.OneAgentSdk.TraceIncomingMessageProcess(messagingSystemInfo);

                    // retrieve Dynatrace tag created using the outgoing message tracer to link both sides together:
                    if (message.Headers.ContainsKey(OneAgentSdkConstants.DYNATRACE_MESSAGE_PROPERTYNAME))
                    {
                        processTracer.SetDynatraceByteTag(message.Headers[OneAgentSdkConstants.DYNATRACE_MESSAGE_PROPERTYNAME]);
                    }

                    // start processing:
                    processTracer.Start();
                    processTracer.SetCorrelationId(message.CorrelationId);           // optional
                    processTracer.SetVendorMessageId(receiveResult.VendorMessageId); // optional
                    try
                    {
                        ProcessMessage(message); // do the work ...
                    }
                    catch (Exception e)
                    {
                        processTracer.Error(e);
                        // handle or rethrow
                        throw e;
                    }
                    finally
                    {
                        processTracer.End();
                    }
                }
                catch (Exception e)
                {
                    receiveTracer.Error(e);
                    // handle or rethrow
                    throw e;
                }
                finally
                {
                    receiveTracer.End();
                }
            });

            server.Start();
            server.Join();
        }