protected virtual void Dispose(bool disposing)
        {
            if (!this.hasDisposed)
            {
                if (disposing)
                {
                    if (this.IsObserverRunning)
                    {
                        this.StopObservers();
                    }

                    if (this.globalShutdownEventHandle != null)
                    {
                        this.globalShutdownEventHandle.Dispose();
                    }

                    if (this.observers?.Count > 0)
                    {
                        foreach (var obs in this.observers)
                        {
                            obs?.Dispose();
                        }

                        this.observers.Clear();
                    }

                    if (FabricClientInstance != null)
                    {
                        FabricClientInstance.Dispose();
                        FabricClientInstance = null;
                    }

                    if (this.cts != null)
                    {
                        this.cts.Dispose();
                        this.cts = null;
                    }

                    // Flush and Dispose all NLog targets. No more logging.
                    Logger.Flush();
                    DataTableFileLogger.Flush();
                    Logger.ShutDown();
                    DataTableFileLogger.ShutDown();

                    this.hasDisposed = true;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ObserverManager"/> class.
        /// </summary>
        public ObserverManager(
            StatelessServiceContext context,
            CancellationToken token)
        {
            this.token = token;
            this.cts   = new CancellationTokenSource();
            this.token.Register(() => { this.ShutdownHandler(this, null); });
            FabricClientInstance = new FabricClient();
            FabricServiceContext = context;
            this.nodeName        = FabricServiceContext?.NodeContext.NodeName;

            // Observer Logger setup...
            string logFolderBasePath = null;
            string observerLogPath   = GetConfigSettingValue(
                ObserverConstants.ObserverLogPath);

            if (!string.IsNullOrEmpty(observerLogPath))
            {
                logFolderBasePath = observerLogPath;
            }
            else
            {
                string logFolderBase = $@"{Environment.CurrentDirectory}\observer_logs";
                logFolderBasePath = logFolderBase;
            }

            // this logs metrics from observers, if enabled, and/or sends
            // telemetry data to your implemented provider...
            this.DataLogger = new DataTableFileLogger();

            // this logs error/warning/info messages for ObserverManager...
            this.Logger         = new Logger("ObserverManager", logFolderBasePath);
            this.HealthReporter = new ObserverHealthReporter(this.Logger);
            this.SetPropertiesFromConfigurationParameters();

            // Populate the Observer list for the sequential run loop...
            this.observers = GetObservers();
        }
        private void LogAllAppResourceDataToCsv(string appName)
        {
            if (!this.CsvFileLogger.EnableCsvLogging && !this.IsTelemetryEnabled)
            {
                return;
            }

            var fileName = appName.Replace(":", string.Empty) +
                           this.NodeName;

            // CPU Time
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "% CPU Time",
                "Average",
                Math.Round(this.allAppCpuData.Where(x => x.Id == appName)
                           .FirstOrDefault().AverageDataValue));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "% CPU Time",
                "Peak",
                Math.Round(Convert.ToDouble(this.allAppCpuData.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));

            // Memory
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "Memory (Working set) MB",
                "Average",
                Math.Round(this.allAppMemDataMB.Where(x => x.Id == appName)
                           .FirstOrDefault().AverageDataValue));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "Memory (Working set) MB",
                "Peak",
                Math.Round(Convert.ToDouble(this.allAppMemDataMB.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "Memory (Percent in use)",
                "Average",
                Math.Round(this.allAppMemDataPercent.Where(x => x.Id == appName)
                           .FirstOrDefault().AverageDataValue));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "Memory (Percent in use)",
                "Peak",
                Math.Round(Convert.ToDouble(this.allAppMemDataPercent.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));

            // IO Read Bytes/s
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "IO Read Bytes/sec",
                "Average",
                Math.Round(this.allAppDiskReadsData.Where(x => x.Id == appName)
                           .FirstOrDefault().AverageDataValue));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "IO Read Bytes/sec",
                "Peak",
                Math.Round(Convert.ToDouble(this.allAppDiskReadsData.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));

            // IO Write Bytes/s
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "IO Write Bytes/sec",
                "Average",
                Math.Round(this.allAppDiskWritesData.Where(x => x.Id == appName)
                           .FirstOrDefault().AverageDataValue));
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "IO Write Bytes/sec",
                "Peak",
                Math.Round(Convert.ToDouble(this.allAppDiskWritesData.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));

            // Network
            this.CsvFileLogger.LogData(
                fileName,
                appName,
                "Active Ports",
                "Total",
                Math.Round(Convert.ToDouble(this.allAppTotalActivePortsData.Where(x => x.Id == appName)
                                            .FirstOrDefault().MaxDataValue)));
            DataTableFileLogger.Flush();
        }
        /// <inheritdoc/>
        public override Task ReportAsync(CancellationToken token)
        {
            try
            {
                token.ThrowIfCancellationRequested();

                if (this.CsvFileLogger.EnableCsvLogging || this.IsTelemetryEnabled)
                {
                    var fileName = "CpuMemFirewallsPorts" + this.NodeName;

                    // Log (csv) system-wide CPU/Mem data...
                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "CPU Time",
                        "Average",
                        Math.Round(this.allCpuDataPrivTime.AverageDataValue));

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "CPU Time",
                        "Peak",
                        Math.Round(this.allCpuDataPrivTime.MaxDataValue));

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "Committed Memory (MB)",
                        "Average",
                        Math.Round(this.allMemDataCommittedBytes.AverageDataValue));

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "Committed Memory (MB)",
                        "Peak",
                        Math.Round(this.allMemDataCommittedBytes.MaxDataValue));

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "All Active Ports",
                        "Total",
                        this.activePortsData.Data[0]);

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "Ephemeral Active Ports",
                        "Total",
                        this.ephemeralPortsData.Data[0]);

                    this.CsvFileLogger.LogData(
                        fileName,
                        this.NodeName,
                        "Firewall Rules",
                        "Total",
                        this.firewallData.Data[0]);

                    DataTableFileLogger.Flush();
                }

                // Report on the global health state (system-wide (node) metrics).
                // User-configurable in NodeObserver.config.json
                var timeToLiveWarning = this.SetTimeToLiveWarning();

                // CPU
                if (this.allCpuDataPrivTime.AverageDataValue > 0)
                {
                    this.ProcessResourceDataReportHealth(
                        this.allCpuDataPrivTime,
                        this.CpuErrorUsageThresholdPct,
                        this.CpuWarningUsageThresholdPct,
                        timeToLiveWarning);
                }

                // Memory
                if (this.allMemDataCommittedBytes.AverageDataValue > 0)
                {
                    this.ProcessResourceDataReportHealth(
                        this.allMemDataCommittedBytes,
                        this.MemErrorUsageThresholdMB,
                        this.MemWarningUsageThresholdMB,
                        timeToLiveWarning);
                }

                if (this.allMemDataPercentUsed.AverageDataValue > 0)
                {
                    this.ProcessResourceDataReportHealth(
                        this.allMemDataPercentUsed,
                        this.MemoryErrorLimitPercent,
                        this.MemoryWarningLimitPercent,
                        timeToLiveWarning);
                }

                // Firewall rules
                this.ProcessResourceDataReportHealth(
                    this.firewallData,
                    this.FirewallRulesErrorThreshold,
                    this.FirewallRulesWarningThreshold,
                    timeToLiveWarning);

                // Ports
                this.ProcessResourceDataReportHealth(
                    this.activePortsData,
                    this.ActivePortsErrorThreshold,
                    this.ActivePortsWarningThreshold,
                    timeToLiveWarning);

                this.ProcessResourceDataReportHealth(
                    this.ephemeralPortsData,
                    this.EphemeralPortsErrorThreshold,
                    this.EphemeralPortsWarningThreshold,
                    timeToLiveWarning);

                return(Task.FromResult(1));
            }
            catch (Exception e)
            {
                if (!(e is OperationCanceledException))
                {
                    this.HealthReporter.ReportFabricObserverServiceHealth(
                        this.FabricServiceContext.ServiceName.OriginalString,
                        this.ObserverName,
                        HealthState.Warning,
                        e.ToString());
                }

                throw;
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ObserverManager"/> class.
        /// </summary>
        public ObserverManager(
            StatelessServiceContext context,
            CancellationToken token)
        {
            this.token = token;
            this.cts   = new CancellationTokenSource();
            this.token.Register(() => { this.ShutdownHandler(this, null); });
            FabricClientInstance = new FabricClient();
            FabricServiceContext = context;
            this.nodeName        = FabricServiceContext?.NodeContext.NodeName;

            // Observer Logger setup.
            string logFolderBasePath = null;
            string observerLogPath   = GetConfigSettingValue(
                ObserverConstants.ObserverLogPath);

            if (!string.IsNullOrEmpty(observerLogPath))
            {
                logFolderBasePath = observerLogPath;
            }
            else
            {
                string logFolderBase = $@"{Environment.CurrentDirectory}\observer_logs";
                logFolderBasePath = logFolderBase;
            }

            // this logs metrics from observers, if enabled, and/or sends
            // telemetry data to your implemented provider.
            this.DataLogger = new DataTableFileLogger();

            // this logs error/warning/info messages for ObserverManager.
            this.Logger         = new Logger("ObserverManager", logFolderBasePath);
            this.HealthReporter = new ObserverHealthReporter(this.Logger);
            this.SetPropertiesFromConfigurationParameters();

            // Populate the Observer list for the sequential run loop.
            this.observers = GetObservers();

            // FabricObserver Internal Diagnostic Telemetry (Non-PII).
            // Internally, TelemetryEvents determines current Cluster Id as a unique identifier for transmitted events.
            if (FabricObserverInternalTelemetryEnabled)
            {
                string codePkgVersion         = FabricServiceContext.CodePackageActivationContext.CodePackageVersion;
                string serviceManifestVersion = FabricServiceContext.CodePackageActivationContext.GetConfigurationPackageObject("Config").Description.ServiceManifestVersion;
                string filepath = Path.Combine(logFolderBasePath, $"fo_telemetry_sent_{codePkgVersion.Replace(".", string.Empty)}_{serviceManifestVersion.Replace(".", string.Empty)}_{FabricServiceContext.NodeContext.NodeType}.txt");
#if !DEBUG
                // If this has already been sent for this activated version (code/config) of nodetype x
                if (File.Exists(filepath))
                {
                    return;
                }
#endif
                this.telemetryEvents = new TelemetryEvents(
                    FabricClientInstance,
                    FabricServiceContext,
                    ServiceEventSource.Current,
                    this.token);

                if (this.telemetryEvents.FabricObserverRuntimeNodeEvent(
                        codePkgVersion,
                        this.GetFabricObserverInternalConfiguration(),
                        "HealthState.Initialized"))
                {
                    // Log a file to prevent re-sending this in case of process restart(s).
                    // This non-PII FO/Cluster info is versioned and should only be sent once per deployment (config or code updates.).
                    _ = this.Logger.TryWriteLogFile(filepath, "_");
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ObserverBase"/> class.
        /// </summary>
        protected ObserverBase()
        {
            ObserverName             = GetType().Name;
            ConfigurationSectionName = ObserverName + "Configuration";
            FabricClientInstance     = ObserverManager.FabricClientInstance;

            if (IsTelemetryProviderEnabled)
            {
                TelemetryClient = ObserverManager.TelemetryClient;
            }

            FabricServiceContext     = ObserverManager.FabricServiceContext;
            NodeName                 = FabricServiceContext.NodeContext.NodeName;
            NodeType                 = FabricServiceContext.NodeContext.NodeType;
            ConfigurationSectionName = ObserverName + "Configuration";

            // Observer Logger setup.
            string logFolderBasePath;
            string observerLogPath = GetSettingParameterValue(
                ObserverConstants.ObserverManagerConfigurationSectionName,
                ObserverConstants.ObserverLogPathParameter);

            if (!string.IsNullOrEmpty(observerLogPath))
            {
                logFolderBasePath = observerLogPath;
            }
            else
            {
                string logFolderBase = Path.Combine(Environment.CurrentDirectory, "observer_logs");
                logFolderBasePath = logFolderBase;
            }

            ObserverLogger = new Logger(ObserverName, logFolderBasePath);

            if (string.IsNullOrEmpty(this.dumpsPath))
            {
                SetDefaultSfDumpPath();
            }

            // DataLogger setup
            if (bool.TryParse(
                    GetSettingParameterValue(
                        ConfigurationSectionName,
                        ObserverConstants.EnableLongRunningCsvLogging),
                    out bool enableDataLogging))
            {
                if (enableDataLogging)
                {
                    CsvFileLogger = new DataTableFileLogger
                    {
                        EnableCsvLogging = enableDataLogging,
                    };

                    string dataLogPath = GetSettingParameterValue(
                        ObserverConstants.ObserverManagerConfigurationSectionName,
                        ObserverConstants.DataLogPathParameter);

                    if (!string.IsNullOrEmpty(dataLogPath))
                    {
                        CsvFileLogger.DataLogFolderPath = dataLogPath;
                    }
                    else
                    {
                        CsvFileLogger.DataLogFolderPath = Path.Combine(Environment.CurrentDirectory, "observer_data_logs");
                    }
                }
            }

            if (string.IsNullOrEmpty(this.dumpsPath))
            {
                SetDefaultSfDumpPath();
            }

            if (!IsTestRun)
            {
                ConfigurationSettings = new Utilities.ConfigSettings(
                    FabricServiceContext.CodePackageActivationContext.GetConfigurationPackageObject("Config").Settings,
                    ConfigurationSectionName);

                EnableVerboseLogging                = ConfigurationSettings.EnableVerboseLogging;
                IsEnabled                           = ConfigurationSettings.IsEnabled;
                IsObserverTelemetryEnabled          = ConfigurationSettings.IsObserverTelemetryEnabled;
                MonitorDuration                     = ConfigurationSettings.MonitorDuration;
                RunInterval                         = ConfigurationSettings.RunInterval;
                ObserverLogger.EnableVerboseLogging = EnableVerboseLogging;
                DataCapacity                        = ConfigurationSettings.DataCapacity;
                UseCircularBuffer                   = ConfigurationSettings.UseCircularBuffer;
            }

            HealthReporter = new ObserverHealthReporter(ObserverLogger);
        }
Exemple #7
0
        public override Task ReportAsync(CancellationToken token)
        {
            try
            {
                token.ThrowIfCancellationRequested();

                if (CsvFileLogger != null && CsvFileLogger.EnableCsvLogging)
                {
                    var fileName = "CpuMemFirewallsPorts" + NodeName;

                    // Log (csv) system-wide CPU/Mem data.
                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "CPU Time",
                        "Average",
                        Math.Round(AllCpuTimeData.AverageDataValue));

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "CPU Time",
                        "Peak",
                        Math.Round(AllCpuTimeData.MaxDataValue));

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "Committed Memory (MB)",
                        "Average",
                        Math.Round(this.allMemDataCommittedBytes.AverageDataValue));

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "Committed Memory (MB)",
                        "Peak",
                        Math.Round(this.allMemDataCommittedBytes.MaxDataValue));

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "All Active Ports",
                        "Total",
                        this.activePortsData.Data[0]);

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "Ephemeral Active Ports",
                        "Total",
                        this.ephemeralPortsData.Data[0]);

                    CsvFileLogger.LogData(
                        fileName,
                        NodeName,
                        "Firewall Rules",
                        "Total",
                        this.firewallData.Data[0]);

                    DataTableFileLogger.Flush();
                }

                // Report on the global health state (system-wide (node) metrics).
                // User-configurable in NodeObserver.config.json
                var timeToLiveWarning = SetHealthReportTimeToLive();

                // CPU
                if (AllCpuTimeData.AverageDataValue > 0)
                {
                    ProcessResourceDataReportHealth(
                        AllCpuTimeData,
                        CpuErrorUsageThresholdPct,
                        CpuWarningUsageThresholdPct,
                        timeToLiveWarning);
                }

                // Memory
                if (this.allMemDataCommittedBytes.AverageDataValue > 0)
                {
                    ProcessResourceDataReportHealth(
                        this.allMemDataCommittedBytes,
                        MemErrorUsageThresholdMb,
                        MemWarningUsageThresholdMb,
                        timeToLiveWarning);
                }

                if (this.allMemDataPercentUsed.AverageDataValue > 0)
                {
                    ProcessResourceDataReportHealth(
                        this.allMemDataPercentUsed,
                        MemoryErrorLimitPercent,
                        MemoryWarningLimitPercent,
                        timeToLiveWarning);
                }

                // Firewall rules
                ProcessResourceDataReportHealth(
                    this.firewallData,
                    FirewallRulesErrorThreshold,
                    FirewallRulesWarningThreshold,
                    timeToLiveWarning);

                // Ports - Active TCP
                ProcessResourceDataReportHealth(
                    this.activePortsData,
                    ActivePortsErrorThreshold,
                    ActivePortsWarningThreshold,
                    timeToLiveWarning);

                // Ports - Active Ephemeral TCP
                ProcessResourceDataReportHealth(
                    this.ephemeralPortsData,
                    EphemeralPortsErrorThreshold,
                    EphemeralPortsWarningThreshold,
                    timeToLiveWarning);

                return(Task.CompletedTask);
            }
            catch (AggregateException e) when(e.InnerException is OperationCanceledException || e.InnerException is TaskCanceledException || e.InnerException is TimeoutException)
            {
                return(Task.CompletedTask);
            }
            catch (Exception e)
            {
                HealthReporter.ReportFabricObserverServiceHealth(
                    FabricServiceContext.ServiceName.OriginalString,
                    ObserverName,
                    HealthState.Warning,
                    $"Unhandled exception re-thrown:{Environment.NewLine}{e}");

                throw;
            }
        }