private EventData ToEventData(LogEvent logEvent)
        {
            EventData eventData = new EventData
            {
                ProviderName = nameof(SerilogInput),
                Timestamp    = logEvent.Timestamp,
                Level        = ToLogLevel[logEvent.Level],
                Keywords     = 0
            };

            var payload = eventData.Payload;

            // Prefer the built-in `Message` and `Exception` properties by adding them to the payload
            // first. If other attached data items have conflicting names, they will be added as
            // `Message_1` and so-on.
            if (logEvent.Exception != null)
            {
                if (logEvent.Level >= LogEventLevel.Error)
                {
                    EventMetadata eventMetadata = new EventMetadata(ExceptionData.ExceptionMetadataKind);
                    eventMetadata.Properties.Add(ExceptionData.ExceptionPropertyMoniker, "Exception");
                    eventData.SetMetadata(eventMetadata);
                }

                eventData.AddPayloadProperty("Exception", logEvent.Exception, healthReporter, nameof(SerilogInput));
            }

            // Inability to render the message, or any other LogEvent property, should not stop us from sending the event down the pipeline
            try
            {
                eventData.AddPayloadProperty("Message", logEvent.RenderMessage(), healthReporter, nameof(SerilogInput));
            }
            catch (Exception e)
            {
                healthReporter.ReportWarning($"{nameof(SerilogInput)}: event message could not be rendered{Environment.NewLine}{e.ToString()}");
            }

            // MessageTemplate is always present on Serilog events
            eventData.AddPayloadProperty("MessageTemplate", logEvent.MessageTemplate.Text, healthReporter, nameof(SerilogInput));

            foreach (var property in logEvent.Properties.Where(property => property.Value != null))
            {
                try
                {
                    eventData.AddPayloadProperty(property.Key, ToRawValue(property.Value), healthReporter, nameof(SerilogInput));
                }
                catch (Exception e)
                {
                    healthReporter.ReportWarning($"{nameof(SerilogInput)}: event property '{property.Key}' could not be rendered{Environment.NewLine}{e.ToString()}");
                }
            }

            return(eventData);
        }
        public static void AddPayloadProperty(IDictionary <string, object> payload, string key, object value, IHealthReporter healthReporter, string context)
        {
            Requires.NotNull(payload, nameof(payload));
            Requires.NotNull(key, nameof(key));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            if (!payload.ContainsKey(key))
            {
                payload.Add(key, value);
                return;
            }

            string newKey;
            int    i = 1;

            //update property key till there is no such key in dict
            do
            {
                newKey = key + "_" + i.ToString("d");
                i++;
            }while (payload.ContainsKey(newKey));

            payload.Add(newKey, value);
            healthReporter.ReportWarning($"The property with the key '{key}' already exist in the event payload. Value was added under key '{newKey}'", context);
        }
        private EventData ToEventData(LoggingEvent loggingEvent)
        {
            var eventData = new EventData
            {
                ProviderName = $"{nameof(Log4netInput)}.{loggingEvent.LoggerName}",
                Timestamp    = loggingEvent.TimeStamp,
                Level        = ToLogLevel[loggingEvent.Level],
                Keywords     = 0,
                Payload      = { { "Message", loggingEvent.MessageObject } }
            };

            if (loggingEvent.ExceptionObject != null)
            {
                eventData.Payload.Add("Exception", loggingEvent.ExceptionObject);
            }

            foreach (var key in loggingEvent.Properties.GetKeys())
            {
                try
                {
                    eventData.AddPayloadProperty(key, loggingEvent.LookupProperty(key), healthReporter, nameof(Log4netInput));
                }
                catch (Exception ex)
                {
                    healthReporter.ReportWarning($"{nameof(Log4netInput)}: event property '{key}' could not be rendered{Environment.NewLine}{ex}");
                }
            }

            return(eventData);
        }
Beispiel #4
0
        public TraceInput(IConfiguration configuration, IHealthReporter healthReporter)
        {
            Validation.Requires.NotNull(configuration, nameof(configuration));
            Validation.Requires.NotNull(healthReporter, nameof(healthReporter));

            this.healthReporter = healthReporter;

            TraceInputConfiguration traceInputConfiguration = new TraceInputConfiguration();
            bool configurationIsValid = true;

            try
            {
                configuration.Bind(traceInputConfiguration);
            }
            catch
            {
                configurationIsValid = false;
            }
            if (!configurationIsValid || !string.Equals(traceInputConfiguration.Type, "trace", StringComparison.OrdinalIgnoreCase))
            {
                healthReporter.ReportWarning($"Invalid {nameof(TraceInput)} configuration encountered: '{configuration.ToString()}'. Error will be used as trace level",
                                             EventFlowContextIdentifiers.Configuration);
            }

            Initialize(traceInputConfiguration);
        }
Beispiel #5
0
 void IObserver <TInput> .OnNext(TInput value)
 {
     if (!target.Post(value))
     {
         healthReporter.ReportWarning("An event was dropped from the diagnostic pipeline because there was not enough capacity", EventFlowContextIdentifiers.Throttling);
     }
 }
        private void Initialize(List <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();

            if (eventSources.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EventSourceInput)}: no event sources configured, the input will not produce any data", EventFlowContextIdentifiers.Configuration);
            }

            var invalidConfigurationItems = new List <EventSourceConfiguration>();

            foreach (var eventSourceConfiguration in eventSources)
            {
                if (!eventSourceConfiguration.Validate())
                {
                    healthReporter.ReportProblem($"{nameof(EventSourceInput)}: configuration for one of the sources is invalid", EventFlowContextIdentifiers.Configuration);
                    invalidConfigurationItems.Add(eventSourceConfiguration);
                }
            }
            // eventSources is a collection created by us, so we can modify it as necessary
            eventSources.RemoveAll(config => invalidConfigurationItems.Contains(config));

            // Special case: because of .NET bug https://github.com/dotnet/coreclr/issues/14434, using Microsoft-ApplicationInsights-Data will result in infinite loop.
            // So we will disable it by default, unless there is explicit configuration for this EventSource
            bool hasConfigForAppInsightsDataSource = eventSources.Any(config =>
                                                                      AppInsightsDataEventSource.Equals(config.ProviderName, StringComparison.Ordinal) ||
                                                                      AppInsightsDataEventSource.Equals(config.DisabledProviderNamePrefix, StringComparison.Ordinal));

            if (!hasConfigForAppInsightsDataSource)
            {
                eventSources.Add(new EventSourceConfiguration()
                {
                    DisabledProviderNamePrefix = AppInsightsDataEventSource
                });
            }

            this.EventSources = eventSources;

            bool haveDisabledSources = this.EventSources.Any(config => !string.IsNullOrWhiteSpace(config.DisabledProviderNamePrefix));

            if (haveDisabledSources)
            {
                this.disabledSources    = new ConcurrentDictionary <string, bool>();
                this.OnEventWrittenImpl = BroadcastEventIfSourceNotDisabled;
            }
            else
            {
                this.OnEventWrittenImpl = BroadcastEvent;
            }

            // Make sure the constructor has run to completion before enabling any sources.
            this.initialization = Task.Run(() =>
            {
                this.constructed = true;
                EnableInitialSources();
            });
        }
Beispiel #7
0
        internal static IConfigurationRoot ApplyFabricConfigurationOverrides(this IConfigurationRoot configurationRoot, IHealthReporter healthReporter)
        {
            Debug.Assert(configurationRoot != null);
            Debug.Assert(healthReporter != null);

            Regex fabricValueReferenceRegex = new Regex(FabricConfigurationValueReference, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(100));

            // Use ToList() to ensure that configuration is fully enumerated before starting to modify it.
            foreach (var kvp in configurationRoot.AsEnumerable().ToList())
            {
                if (kvp.Value == null)
                {
                    continue;
                }

                try
                {
                    Match valueReferenceMatch = fabricValueReferenceRegex.Match(kvp.Value);
                    if (valueReferenceMatch.Success)
                    {
                        string valueReferencePath = ConfigurationPath.Combine(valueReferenceMatch.Groups["section"].Value, valueReferenceMatch.Groups["name"].Value);
                        string newValue           = configurationRoot[valueReferencePath];
                        if (string.IsNullOrEmpty(newValue))
                        {
                            healthReporter.ReportWarning(
                                $"Configuration value reference '{kvp.Value}' was encountered but no corresponding configuration value was found using path '{valueReferencePath}'",
                                EventFlowContextIdentifiers.Configuration);
                        }
                        else
                        {
                            configurationRoot[kvp.Key] = newValue;
                        }
                    }
                }
                catch (RegexMatchTimeoutException)
                {
                    healthReporter.ReportWarning(
                        $"Configuration entry with key '{kvp.Key}' and value '{kvp.Value}' could not be checked if it represents a configuration value reference--a timeout occurred when the value was being parsed.",
                        EventFlowContextIdentifiers.Configuration);
                    continue;
                }
            }

            return(configurationRoot);
        }
Beispiel #8
0
        private EventData ToEventData(LogEvent logEvent)
        {
            EventData eventData = new EventData
            {
                ProviderName = nameof(SerilogInput),
                Timestamp    = logEvent.Timestamp,
                Level        = ToLogLevel[logEvent.Level],
                Keywords     = 0
            };

            var payload = eventData.Payload;

            if (logEvent.Exception != null)
            {
                payload["Exception"] = logEvent.Exception;
            }

            // Inability to render the message, or any other LogEvent property, should not stop us from sending the event down the pipeline
            try
            {
                payload["Message"] = logEvent.RenderMessage();
            }
            catch (Exception e)
            {
                healthReporter.ReportWarning($"{nameof(SerilogInput)}: event message could not be rendered{Environment.NewLine}{e.ToString()}");
            }

            foreach (var property in logEvent.Properties.Where(property => property.Value != null))
            {
                try
                {
                    payload[property.Key] = ToRawValue(property.Value);
                }
                catch (Exception e)
                {
                    healthReporter.ReportWarning($"{nameof(SerilogInput)}: event property '{property.Key}' could not be rendered{Environment.NewLine}{e.ToString()}");
                }
            }

            return(eventData);
        }
        public void Activate()
        {
            if (this.isDisposed)
            {
                throw new ObjectDisposedException(nameof(EtwInput));
            }

            if (this.session != null)
            {
                throw new InvalidOperationException($"{nameof(EtwInput)} has already been activated");
            }

            if (this.Providers.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EtwInput)}: no providers configured", nameof(EtwInput));
                return;
            }

            this.session = SessionFactory();

            foreach (var providerConfiguration in this.Providers)
            {
                string validationError;
                if (!providerConfiguration.Validate(out validationError))
                {
                    this.healthReporter.ReportWarning($"{nameof(EtwInput)}: one of the providers is configured improperly. {validationError}", EventFlowContextIdentifiers.Configuration);
                    continue;
                }
                if (providerConfiguration.ProviderGuid != Guid.Empty)
                {
                    this.session.EnableProvider(providerConfiguration.ProviderGuid, providerConfiguration.Level, (ulong)providerConfiguration.Keywords);
                }
                else
                {
                    this.session.EnableProvider(providerConfiguration.ProviderName, providerConfiguration.Level, (ulong)providerConfiguration.Keywords);
                }
            }

            // Also enable .NET Task Parallel Library hierarchical activity tracking
            this.session.EnableProvider(TplActivities.TplEventSourceGuid, TraceEventLevel.Always, TplActivities.TaskFlowActivityIdsKeyword);

            Task.Factory.StartNew(() =>
            {
                try
                {
                    this.session.Process((eventData) => this.subject.OnNext(eventData));
                }
                catch (Exception e)
                {
                    this.healthReporter.ReportProblem($"{nameof(EtwInput)}: ETW session has terminated unexpectedly and events are no longer collected. {e.ToString()}");
                }
            }, TaskCreationOptions.LongRunning);
        }
        public static void AddPayloadProperty(IDictionary <string, object> payload, string key, object value, IHealthReporter healthReporter, string context)
        {
            Requires.NotNull(payload, nameof(payload));
            Requires.NotNull(key, nameof(key));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            if (!payload.TryGetValue(key, out var existingValue))
            {
                payload.Add(key, value);
                return;
            }
            else if ((existingValue?.Equals(value)).GetValueOrDefault(false))
            {
                // Existing value with same key is equivalent to the input value
                // We can return immediately to avoid adding duplicate key/value into the payload
                return;
            }

            string newKey;
            int    i = 1;

            //update property key till there is no such key in dict
            do
            {
                newKey = key + "_" + i.ToString("d");
                i++;
            }while (payload.TryGetValue(newKey, out existingValue) && !(existingValue?.Equals(value)).GetValueOrDefault(false));

            if (!payload.ContainsKey(newKey))
            {
                payload.Add(newKey, value);
                healthReporter.ReportWarning($"The property with the key '{key}' already exist in the event payload. Value was added under key '{newKey}'", context);
            }
            else
            {
                healthReporter.ReportWarning($"The property with the key '{key}' already exist in the event payload with equivalent value under key '{newKey}'. Value was not re-added", context);
                return;
            }
        }
Beispiel #11
0
        private void Initialize(IReadOnlyCollection <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();

            this.EventSources = eventSources;
            if (this.EventSources.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EventSourceInput)}: no event sources configured", nameof(EventSourceInput));
            }

            // Make sure the constructor has run to completion before enabling any sources.
            this.initialization = Task.Run(() =>
            {
                this.constructed = true;
                EnableInitialSources();
            });
        }
        private void Initialize(IReadOnlyCollection <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();

            this.EventSources = eventSources;
            if (this.EventSources.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EventSourceInput)}: no event sources configured", nameof(EventSourceInput));
                return;
            }

            lock (this)  // See OnEventSourceCreated() for explanation why we are locking on 'this' here.
            {
                EnableInitialSources();
                this.constructed = true;
            }
        }
Beispiel #13
0
        private void Initialize(List <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();

            if (eventSources.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EventSourceInput)}: no event sources configured", EventFlowContextIdentifiers.Configuration);
            }

            var invalidConfigurationItems = new List <EventSourceConfiguration>();

            foreach (var eventSourceConfiguration in eventSources)
            {
                if (!eventSourceConfiguration.Validate())
                {
                    healthReporter.ReportProblem($"{nameof(EventSourceInput)}: configuration for one of the sources is invalid", EventFlowContextIdentifiers.Configuration);
                    invalidConfigurationItems.Add(eventSourceConfiguration);
                }
            }
            // eventSources is a collection created by us, so we can modify it as necessary
            eventSources.RemoveAll(config => invalidConfigurationItems.Contains(config));
            this.EventSources = eventSources;

            bool haveDisabledSources = this.EventSources.Any(config => !string.IsNullOrWhiteSpace(config.DisabledProviderNamePrefix));

            if (haveDisabledSources)
            {
                this.disabledSources    = new ConcurrentDictionary <string, bool>();
                this.OnEventWrittenImpl = BroadcastEventIfSourceNotDisabled;
            }
            else
            {
                this.OnEventWrittenImpl = BroadcastEvent;
            }

            // Make sure the constructor has run to completion before enabling any sources.
            this.initialization = Task.Run(() =>
            {
                this.constructed = true;
                EnableInitialSources();
            });
        }
Beispiel #14
0
        private TypeMappingDescriptor <object> applyTypeMapping(TypeMappingDescriptor <object> tm)
        {
            return(tm.Properties(pd =>
            {
                PropertiesDescriptor <object> properties = pd;
                foreach (var propMapping in configuration.Mappings.Properties)
                {
                    string propertyType = propMapping.Value.Type;
                    string propertyName = propMapping.Key;

                    if (!typeToPropertiesDesctiptorFunc.ContainsKey(propertyType))
                    {
                        string errorMessage = $"{nameof(ElasticSearchOutput)}: {propertyName} property mapping could not be set because configured type ({propertyType}) is not supported.";
                        healthReporter.ReportWarning(errorMessage, EventFlowContextIdentifiers.Output);
                    }
                    else
                    {
                        properties = typeToPropertiesDesctiptorFunc[propertyType](properties, propertyName);
                    }
                }

                return properties;
            }));
        }
        private EventData ToEventData(LogEventInfo logEvent)
        {
            var providerName = string.Empty;

            try
            {
                providerName = ProviderName?.Render(logEvent);
            }
            catch (Exception ex)
            {
                NLog.Common.InternalLogger.Warn(ex, NLogTargetTypeName + "(Name={0}): Failed to render event providername", Name);
                _healthReporter.ReportWarning($"{nameof(NLogInput)}: event providername could not be rendered{Environment.NewLine}{ex.ToString()}");
            }

            if (string.IsNullOrEmpty(providerName))
            {
                providerName = string.IsNullOrEmpty(logEvent.LoggerName) ? nameof(NLogInput) : logEvent.LoggerName;
            }

            EventData eventData = new EventData
            {
                ProviderName = providerName,
                Timestamp    = logEvent.TimeStamp.ToUniversalTime(),
                Level        = ToLogLevel[logEvent.Level],
                Keywords     = 0,
            };

            var payload = eventData.Payload;

            // Prefer the built-in `Message` and `Exception` properties by adding them to the payload
            // first. If other attached data items have conflicting names, they will be added as
            // `Message_1` and so-on.
            if (logEvent.Exception != null)
            {
                if (logEvent.Level.Ordinal >= NLog.LogLevel.Error.Ordinal)
                {
                    EventMetadata eventMetadata = new EventMetadata(ExceptionData.ExceptionMetadataKind);
                    eventMetadata.Properties.Add(ExceptionData.ExceptionPropertyMoniker, "Exception");
                    eventData.SetMetadata(eventMetadata);
                }

                eventData.AddPayloadProperty("Exception", logEvent.Exception, _healthReporter, nameof(NLogInput));
            }

            // Inability to render the message, or any other LogEvent property, should not stop us from sending the event down the pipeline
            try
            {
                eventData.AddPayloadProperty("Message", RenderLogEvent(Layout, logEvent), _healthReporter, nameof(NLogInput));
            }
            catch (Exception ex)
            {
                NLog.Common.InternalLogger.Warn(ex, NLogTargetTypeName + "(Name={0}): Failed to render event message", Name);
                _healthReporter.ReportWarning($"{nameof(NLogInput)}: event message could not be rendered{Environment.NewLine}{ex.ToString()}");
                eventData.AddPayloadProperty("Message", logEvent.FormattedMessage, _healthReporter, nameof(NLogInput));
            }

            if (ContextProperties.Count > 0)
            {
                // Include fixed properties like ThreadId, HostName, MessageTemplate, etc.
                CaptureTargetContextEventData(logEvent, eventData);
            }

            if (IncludeEventProperties && logEvent.HasProperties)
            {
                // Include properties coming from LogEvent
                CaptureLogEventPropertiesEventData(logEvent.Properties, eventData);
            }

            if (IncludeMdc || IncludeMdlc)
            {
                // Include any random bonus information
                CaptureLogEventContextProperties(GetContextProperties(logEvent), eventData);
            }

            return(eventData);
        }
Beispiel #16
0
 public static void ReportThrottling(this IHealthReporter healthReporter)
 {
     healthReporter.ReportWarning("An event was dropped from the diagnostic pipeline because there was not enough capacity",
                                  EventFlowContextIdentifiers.Throttling);
 }
        private static void ReportInvalidPipelineConfiguration(IHealthReporter healthReporter)
        {
            var errMsg = $"{nameof(DiagnosticPipelineFactory)}: pipeline settings configuration section is invalid--will use default settings for the diagnostic pipeline";

            healthReporter.ReportWarning(errMsg);
        }
        private static void CreateItemFactories(
            IConfiguration configuration,
            IHealthReporter healthReporter,
            out IDictionary <string, string> inputFactories,
            out IDictionary <string, string> outputFactories,
            out IDictionary <string, string> filterFactories)
        {
            Debug.Assert(configuration != null);
            Debug.Assert(healthReporter != null);

            inputFactories = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            inputFactories["EventSource"]        = "Microsoft.Diagnostics.EventFlow.Inputs.EventSourceInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.EventSource";
            inputFactories["PerformanceCounter"] = "Microsoft.Diagnostics.EventFlow.Inputs.PerformanceCounterInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.PerformanceCounter";
            inputFactories["Trace"]   = "Microsoft.Diagnostics.EventFlow.Inputs.TraceInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.Trace";
            inputFactories["Serilog"] = "Microsoft.Diagnostics.EventFlow.Inputs.SerilogInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.Serilog";
            inputFactories["Microsoft.Extensions.Logging"] = "Microsoft.Diagnostics.EventFlow.Inputs.LoggerInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.MicrosoftLogging";
            inputFactories["ETW"] = "Microsoft.Diagnostics.EventFlow.Inputs.EtwInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.Etw";
            inputFactories["ApplicationInsights"] = "Microsoft.Diagnostics.EventFlow.Inputs.ApplicationInsightsInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.ApplicationInsights";
            inputFactories["Log4net"]             = "Microsoft.Diagnostics.EventFlow.Inputs.Log4netFactory, Microsoft.Diagnostics.EventFlow.Inputs.Log4net";
            inputFactories["NLog"]             = "Microsoft.Diagnostics.EventFlow.Inputs.NLogInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.NLog";
            inputFactories["DiagnosticSource"] = "Microsoft.Diagnostics.EventFlow.Inputs.DiagnosticSource.DiagnosticSourceInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.DiagnosticSource";

            outputFactories = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            outputFactories["ApplicationInsights"] = "Microsoft.Diagnostics.EventFlow.Outputs.ApplicationInsightsOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.ApplicationInsights";
            outputFactories["StdOutput"]           = "Microsoft.Diagnostics.EventFlow.Outputs.StdOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.StdOutput";
            outputFactories["EventHub"]            = "Microsoft.Diagnostics.EventFlow.Outputs.EventHubOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.EventHub";
            outputFactories["ElasticSearch"]       = "Microsoft.Diagnostics.EventFlow.Outputs.ElasticSearchOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.ElasticSearch";
            outputFactories["OmsOutput"]           = "Microsoft.Diagnostics.EventFlow.Outputs.OmsOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.Oms";
            outputFactories["Http"] = "Microsoft.Diagnostics.EventFlow.Outputs.HttpOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.HttpOutput";

            filterFactories             = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            filterFactories["metadata"] = "Microsoft.Diagnostics.EventFlow.Filters.EventMetadataFilterFactory, Microsoft.Diagnostics.EventFlow.Core";
            filterFactories["drop"]     = "Microsoft.Diagnostics.EventFlow.Filters.DropFilterFactory, Microsoft.Diagnostics.EventFlow.Core";

            // read 3rd party plugins
            IConfiguration extensionsConfiguration = configuration.GetSection("extensions");

            foreach (var extension in extensionsConfiguration.GetChildren())
            {
                var extConfig = new ExtensionsConfiguration();
                extension.Bind(extConfig);

                IDictionary <string, string> targetFactories = null;
                if (string.Equals(extConfig.Category, ExtensionCategories.InputFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = inputFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.OutputFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = outputFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.FilterFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = filterFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.HealthReporter, StringComparison.OrdinalIgnoreCase))
                {
                    // Health reporter should have been created earlier, so skip
                    continue;
                }
                else
                {
                    healthReporter.ReportWarning($"Unrecognized extension category: {extConfig.Category}");
                    continue;
                }

                if (!string.IsNullOrEmpty(extConfig.Type) && !string.IsNullOrEmpty(extConfig.QualifiedTypeName))
                {
                    targetFactories[extConfig.Type] = extConfig.QualifiedTypeName;
                }
                else
                {
                    healthReporter.ReportWarning($"Invalid extension configuration is skipped. Category: {extConfig.Category}, Type: {extConfig.Type}, QualifiedTypeName: {extConfig.QualifiedTypeName}");
                }
            }
        }
Beispiel #19
0
        public async Task SendEventsAsync(IReadOnlyCollection <EventData> events, long transmissionSequenceNumber, CancellationToken cancellationToken)
        {
            // Use a "Supressed" transaction scope to not be affected by callers rolling backs
            using (var scope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
            {
                try
                {
                    using (SqlConnection connection = new SqlConnection(ConnectionSettings.ConnectionString))
                    {
                        await connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                        using (SqlCommand command = CreateCommand(connection))
                        {
                            var transactionName = String.Concat(nameof(SqlTableOutput), transmissionSequenceNumber);

                            using (command.Transaction = connection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted, transactionName))
                            {
                                try
                                {
                                    var inserted = 0;
                                    command.Prepare();
#if DEBUG
                                    Console.WriteLine($"{nameof(SqlTableOutput)}: will try to insert #{events.Count} events into SQL Server database");
#endif
                                    // Execute insert for each row in table
                                    foreach (var row in CreateEventsDataTable(events))
                                    {
                                        foreach (var col in row)
                                        {
                                            command.Parameters[String.Concat(PARM_PREFIX, col.Key)].Value = col.Value ?? DBNull.Value;
                                        }

                                        if (cancellationToken.IsCancellationRequested)
                                        {
                                            return;
                                        }

                                        var result = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);

                                        command.Transaction.Save(transactionName);
                                        inserted += result;
                                    }
                                    command.Transaction.Commit();
                                    _healthReporter.ReportHealthy($"{nameof(SqlTableOutput)}: #{inserted} events written to SQL Server database", EventFlowContextIdentifiers.Output);
#if DEBUG
                                    Console.WriteLine($"{nameof(SqlTableOutput)}: #{inserted} events written to SQL Server database");
#endif
                                }
                                catch (Exception sqlex)
                                {
                                    _healthReporter.ReportWarning($"{nameof(SqlTableOutput)}: error writing data to SQL database. {sqlex.Message}", EventFlowContextIdentifiers.Output);
#if DEBUG
                                    Console.WriteLine($"{nameof(SqlTableOutput)}: error writing data to SQL database. {sqlex.Message}");
                                    Console.WriteLine(sqlex.StackTrace);
#endif

                                    try
                                    {
                                        command.Transaction.Rollback(transactionName);
                                        connection.Close();
                                    }
                                    catch (Exception rex)
                                    {
                                        _healthReporter.ReportWarning($"{nameof(SqlTableOutput)}: error rolling back. {rex.Message}", EventFlowContextIdentifiers.Output);
#if DEBUG
                                        Console.WriteLine($"{nameof(SqlTableOutput)}: error rolling back. {rex.Message}");
                                        Console.WriteLine(rex.StackTrace);
#endif
                                    }
                                    throw;
                                }
                            }
                        }
                        connection.Close();
                    }

                    // Not really needed, since the scope is "Suppressed"
                    scope.Complete();
                }
                catch (Exception ex)
                {
                    _healthReporter.ReportProblem($"{nameof(SqlTableOutput)}: write of events data to SQL Server database has failed. {ex.Message}", EventFlowContextIdentifiers.Output);
#if DEBUG
                    Console.WriteLine($"{nameof(SqlTableOutput)}: write of events data to SQL Server database has failed. {ex.Message}");
                    Console.WriteLine(ex.StackTrace);
#endif
                }
            }
        }