/// <summary>
        /// Configure the bus to capture metrics for publication using Prometheus.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="configureOptions"></param>
        /// <param name="serviceName">
        /// The service name for metrics reporting, defaults to the current process main module filename
        /// </param>
        public static void UsePrometheusMetrics(this IBusFactoryConfigurator configurator,
                                                Action <PrometheusMetricsOptions> configureOptions = null,
                                                string serviceName = default)
        {
            var options = PrometheusMetricsOptions.CreateDefault();

            configureOptions?.Invoke(options);

            PrometheusMetrics.TryConfigure(GetServiceName(serviceName), options);

            configurator.ConnectConsumerConfigurationObserver(new PrometheusConsumerConfigurationObserver());
            configurator.ConnectHandlerConfigurationObserver(new PrometheusHandlerConfigurationObserver());
            configurator.ConnectSagaConfigurationObserver(new PrometheusSagaConfigurationObserver());
            configurator.ConnectActivityConfigurationObserver(new PrometheusActivityConfigurationObserver());
            configurator.ConnectEndpointConfigurationObserver(new PrometheusReceiveEndpointConfiguratorObserver());
            configurator.ConnectBusObserver(new PrometheusBusObserver());
        }
        public static void TryConfigure(string serviceName, PrometheusMetricsOptions options)
        {
            if (_isConfigured)
            {
                return;
            }

            _serviceLabel = serviceName;

            string[] serviceLabels = { options.ServiceNameLabel };

            string[] endpointLabels      = { options.ServiceNameLabel, options.EndpointLabel };
            string[] endpointFaultLabels = { options.ServiceNameLabel, options.EndpointLabel, options.ExceptionTypeLabel };

            string[] messageLabels      = { options.ServiceNameLabel, options.MessageTypeLabel };
            string[] messageFaultLabels = { options.ServiceNameLabel, options.MessageTypeLabel, options.ExceptionTypeLabel };

            string[] executeLabels      = { options.ServiceNameLabel, options.ActivityNameLabel, options.ArgumentTypeLabel };
            string[] executeFaultLabels = { options.ServiceNameLabel, options.ActivityNameLabel, options.ArgumentTypeLabel, options.ExceptionTypeLabel };

            string[] compensateLabels        = { options.ServiceNameLabel, options.ActivityNameLabel, options.LogTypeLabel };
            string[] compensateFailureLabels = { options.ServiceNameLabel, options.ActivityNameLabel, options.LogTypeLabel, options.ExceptionTypeLabel };

            string[] consumerLabels      = { options.ServiceNameLabel, options.MessageTypeLabel, options.ConsumerTypeLabel };
            string[] consumerFaultLabels = { options.ServiceNameLabel, options.MessageTypeLabel, options.ConsumerTypeLabel, options.ExceptionTypeLabel };

            // Counters

            _receiveTotal = Metrics.CreateCounter(
                options.ReceiveTotal,
                "Total number of messages received",
                new CounterConfiguration {
                LabelNames = endpointLabels
            });

            _receiveFaultTotal = Metrics.CreateCounter(
                options.ReceiveFaultTotal,
                "Total number of messages receive faults",
                new CounterConfiguration {
                LabelNames = endpointFaultLabels
            });

            _consumeTotal = Metrics.CreateCounter(
                options.ConsumeTotal,
                "Total number of messages consumed",
                new CounterConfiguration {
                LabelNames = consumerLabels
            });

            _consumeFaultTotal = Metrics.CreateCounter(
                options.ConsumeFaultTotal,
                "Total number of message consume faults",
                new CounterConfiguration {
                LabelNames = consumerFaultLabels
            });

            _consumeRetryTotal = Metrics.CreateCounter(
                options.ConsumeRetryTotal,
                "Total number of message consume faults",
                new CounterConfiguration {
                LabelNames = consumerFaultLabels
            });

            _publishTotal = Metrics.CreateCounter(
                options.PublishTotal,
                "Total number of messages published",
                new CounterConfiguration {
                LabelNames = messageLabels
            });

            _publishFaultTotal = Metrics.CreateCounter(
                options.PublishFaultTotal,
                "Total number of message publish faults",
                new CounterConfiguration {
                LabelNames = messageFaultLabels
            });

            _sendTotal = Metrics.CreateCounter(
                options.SendTotal,
                "Total number of messages sent",
                new CounterConfiguration {
                LabelNames = messageLabels
            });

            _sendFaultTotal = Metrics.CreateCounter(
                options.SendFaultTotal,
                "Total number of message send faults",
                new CounterConfiguration {
                LabelNames = messageFaultLabels
            });

            _executeTotal = Metrics.CreateCounter(
                options.ActivityExecuteTotal,
                "Total number of activities executed",
                new CounterConfiguration {
                LabelNames = executeLabels
            });

            _executeFaultTotal = Metrics.CreateCounter(
                options.ActivityExecuteFaultTotal,
                "Total number of activity execution faults",
                new CounterConfiguration {
                LabelNames = executeFaultLabels
            });

            _compensateTotal = Metrics.CreateCounter(
                options.ActivityCompensateTotal,
                "Total number of activities compensated",
                new CounterConfiguration {
                LabelNames = compensateLabels
            });

            _compensateFailureTotal = Metrics.CreateCounter(
                options.ActivityCompensateFailureTotal,
                "Total number of activity compensation failures",
                new CounterConfiguration {
                LabelNames = compensateFailureLabels
            });

            // Gauges

            _busInstances = Metrics.CreateGauge(
                options.BusInstances,
                "Number of bus instances",
                new GaugeConfiguration {
                LabelNames = serviceLabels
            });

            _endpointInstances = Metrics.CreateGauge(
                options.EndpointInstances,
                "Number of receive endpoint instances",
                new GaugeConfiguration {
                LabelNames = endpointLabels
            });

            _receiveInProgress = Metrics.CreateGauge(
                options.ReceiveInProgress,
                "Number of messages being received",
                new GaugeConfiguration {
                LabelNames = endpointLabels
            });

            _handlerInProgress = Metrics.CreateGauge(
                options.HandlerInProgress,
                "Number of handlers in progress",
                new GaugeConfiguration {
                LabelNames = messageLabels
            });

            _consumerInProgress = Metrics.CreateGauge(
                options.ConsumerInProgress,
                "Number of consumers in progress",
                new GaugeConfiguration {
                LabelNames = consumerLabels
            });

            _sagaInProgress = Metrics.CreateGauge(
                options.SagaInProgress,
                "Number of sagas in progress",
                new GaugeConfiguration {
                LabelNames = consumerLabels
            });

            _executeInProgress = Metrics.CreateGauge(
                options.ExecuteInProgress,
                "Number of activity executions in progress",
                new GaugeConfiguration {
                LabelNames = executeLabels
            });

            _compensateInProgress = Metrics.CreateGauge(
                options.CompensateInProgress,
                "Number of activity compensations in progress",
                new GaugeConfiguration {
                LabelNames = compensateLabels
            });

            // Histograms

            _receiveDuration = Metrics.CreateHistogram(
                options.ReceiveDuration,
                "Elapsed time spent receiving a message, in seconds",
                new HistogramConfiguration
            {
                LabelNames = endpointLabels,
                Buckets    = options.HistogramBuckets
            });

            _consumeDuration = Metrics.CreateHistogram(
                options.ConsumeDuration,
                "Elapsed time spent consuming a message, in seconds",
                new HistogramConfiguration
            {
                LabelNames = consumerLabels,
                Buckets    = options.HistogramBuckets
            });

            _deliveryDuration = Metrics.CreateHistogram(
                options.DeliveryDuration,
                "Elapsed time between when the message was sent and when it was consumed, in seconds.",
                new HistogramConfiguration
            {
                LabelNames = consumerLabels,
                Buckets    = options.HistogramBuckets
            });

            _executeDuration = Metrics.CreateHistogram(
                options.ActivityExecuteDuration,
                "Elapsed time spent executing an activity, in seconds",
                new HistogramConfiguration
            {
                LabelNames = executeLabels,
                Buckets    = options.HistogramBuckets
            });

            _compensateDuration = Metrics.CreateHistogram(
                options.ActivityCompensateDuration,
                "Elapsed time spent compensating an activity, in seconds",
                new HistogramConfiguration
            {
                LabelNames = compensateLabels,
                Buckets    = options.HistogramBuckets
            });

            _isConfigured = true;
        }