3.2.6 (DEV), Bug Fix: ClearData (AppObserver).

This commit is contained in:
Charles Torre 2023-03-14 18:37:07 -07:00
Родитель f18e2737c6
Коммит 53721510bf
42 изменённых файлов: 17087 добавлений и 16651 удалений

Просмотреть файл

@ -1,34 +1,34 @@
[string] $scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
function Build-SFPkg {
param (
[string]
$packageId,
[string]
$basePath
)
$ProgressPreference = "SilentlyContinue"
[string] $outputDir = "$scriptPath\bin\release\FabricObserver\SFPkgs"
[string] $zipPath = "$outputDir\$($packageId).zip"
[System.IO.Directory]::CreateDirectory($outputDir) | Out-Null
Compress-Archive "$basePath\*" $zipPath -Force
Move-Item -Path $zipPath -Destination ($zipPath.Replace(".zip", ".sfpkg"))
}
try {
Push-Location $scriptPath
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Linux.SelfContained.3.2.5" "$scriptPath\bin\release\FabricObserver\linux-x64\self-contained\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Linux.FrameworkDependent.3.2.5" "$scriptPath\bin\release\FabricObserver\linux-x64\framework-dependent\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained.3.2.5" "$scriptPath\bin\release\FabricObserver\win-x64\self-contained\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Windows.FrameworkDependent.3.2.5" "$scriptPath\bin\release\FabricObserver\win-x64\framework-dependent\FabricObserverType"
}
finally {
Pop-Location
[string] $scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
function Build-SFPkg {
param (
[string]
$packageId,
[string]
$basePath
)
$ProgressPreference = "SilentlyContinue"
[string] $outputDir = "$scriptPath\bin\release\FabricObserver\SFPkgs"
[string] $zipPath = "$outputDir\$($packageId).zip"
[System.IO.Directory]::CreateDirectory($outputDir) | Out-Null
Compress-Archive "$basePath\*" $zipPath -Force
Move-Item -Path $zipPath -Destination ($zipPath.Replace(".zip", ".sfpkg"))
}
try {
Push-Location $scriptPath
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Linux.SelfContained.3.2.6" "$scriptPath\bin\release\FabricObserver\linux-x64\self-contained\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Linux.FrameworkDependent.3.2.6" "$scriptPath\bin\release\FabricObserver\linux-x64\framework-dependent\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained.3.2.6" "$scriptPath\bin\release\FabricObserver\win-x64\self-contained\FabricObserverType"
Build-SFPkg "Microsoft.ServiceFabricApps.FabricObserver.Windows.FrameworkDependent.3.2.6" "$scriptPath\bin\release\FabricObserver\win-x64\framework-dependent\FabricObserverType"
}
finally {
Pop-Location
}

Просмотреть файл

@ -1,42 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="3.3.0">
<id>%PACKAGE_ID%</id>
<version>2.2.2</version>
<releaseNotes>
- ClusterObserver now ships only as a .NET 6 application and targets SF Runtime versions 9 and higher.
- Several core improvements and better support for emitting useful health information for any SF entity, regardless of health event origin (e.g., from a service like FabricObserver or not).
- Support for FabricObserver's updated telemetry data types.
- Bug fixes.
- It is recommended that you update to this version if you also deploy FabricObserver 3.2.5.
</releaseNotes>
<authors>Microsoft</authors>
<license type="expression">MIT</license>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<title>Service Fabric ClusterObserver Application</title>
<icon>icon.png</icon>
<readme>conuget.md</readme>
<language>en-US</language>
<description>This package contains the Service Fabric ClusterObserver(CO) Application - built for .NET 6.0 and SF Runtime 9.x. CO is a highly configurable and extensible Service Fabric stateless service that monitors aggregated cluster health and emits SF entity-specific telemetry. It is designed to be run in Service Fabric Windows and Linux clusters. This package contains the entire application and can be used to build .NET Standard 2.0 observer plugins. NOTE: If you want to target .NET 6 for your plugins, then you must use Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.5 nuget package to build them.</description>
<contentFiles>
<files include="**" buildAction="None" copyToOutput="true" />
</contentFiles>
<dependencies>
<group targetFramework="net6.0">
<dependency id="Microsoft.ServiceFabric.Services" version="6.0.1017" />
<dependency id="Microsoft.ServiceFabricApps.FabricObserver.Extensibility" version="3.2.5" />
</group>
</dependencies>
<projectUrl>https://aka.ms/sf/FabricObserver</projectUrl>
<tags>azure service-fabric cluster-observer utility watchdog-service observability</tags>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
</metadata>
<files>
<file src="**" target="contentFiles\any\any" />
<file src="ClusterObserverPkg\Code\ClusterObserver.dll" target="lib\net6.0" />
<file src="ClusterObserverPkg\Code\FabricObserver.Extensibility.dll" target="lib\net6.0" />
<file src="ClusterObserverPkg\Code\TelemetryLib.dll" target="lib\net6.0" />
<file src="%ROOT_PATH%\icon.png" target="" />
<file src="%ROOT_PATH%\conuget.md" target="" />
</files>
</package>
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="3.3.0">
<id>%PACKAGE_ID%</id>
<version>2.2.3</version>
<releaseNotes>
</releaseNotes>
<authors>Microsoft</authors>
<license type="expression">MIT</license>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<title>Service Fabric ClusterObserver Application</title>
<icon>icon.png</icon>
<readme>conuget.md</readme>
<language>en-US</language>
<description>This package contains the Service Fabric ClusterObserver(CO) Application - built for .NET 6.0 and SF Runtime 9.x. CO is a highly configurable and extensible Service Fabric stateless service that monitors aggregated cluster health and emits SF entity-specific telemetry. It is designed to be run in Service Fabric Windows and Linux clusters. This package contains the entire application and can be used to build .NET Standard 2.0 observer plugins. NOTE: If you want to target .NET 6 for your plugins, then you must use Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.6 nuget package to build them.</description>
<contentFiles>
<files include="**" buildAction="None" copyToOutput="true" />
</contentFiles>
<dependencies>
<group targetFramework="net6.0">
<dependency id="Microsoft.ServiceFabric.Services" version="6.0.1017" />
<dependency id="Microsoft.ServiceFabricApps.FabricObserver.Extensibility" version="3.2.6" />
</group>
</dependencies>
<projectUrl>https://aka.ms/sf/FabricObserver</projectUrl>
<tags>azure service-fabric cluster-observer utility watchdog-service observability</tags>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
</metadata>
<files>
<file src="**" target="contentFiles\any\any" />
<file src="ClusterObserverPkg\Code\ClusterObserver.dll" target="lib\net6.0" />
<file src="ClusterObserverPkg\Code\FabricObserver.Extensibility.dll" target="lib\net6.0" />
<file src="ClusterObserverPkg\Code\TelemetryLib.dll" target="lib\net6.0" />
<file src="%ROOT_PATH%\icon.png" target="" />
<file src="%ROOT_PATH%\conuget.md" target="" />
</files>
</package>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,38 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}</ProjectGuid>
<RootNamespace>ClusterObserver</RootNamespace>
<AssemblyName>ClusterObserver</AssemblyName>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<TargetLatestRuntimePatch>True</TargetLatestRuntimePatch>
<Copyright>Copyright © 2022</Copyright>
<Product>ClusterObserver</Product>
<Version>2.2.2</Version>
<FileVersion>2.2.2</FileVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<StartupObject>ClusterObserver.Program</StartupObject>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Utilities\ClusterIdentificationUtility.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="ApplicationInsights.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ServiceFabric.Services" Version="6.0.1017" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FabricObserver.Extensibility\FabricObserver.Extensibility.csproj" />
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="PackageRoot\Data\Plugins\" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}</ProjectGuid>
<RootNamespace>ClusterObserver</RootNamespace>
<AssemblyName>ClusterObserver</AssemblyName>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<TargetLatestRuntimePatch>True</TargetLatestRuntimePatch>
<Copyright>Copyright © 2022</Copyright>
<Product>ClusterObserver</Product>
<Version>2.2.3</Version>
<FileVersion>2.2.3</FileVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<StartupObject>ClusterObserver.Program</StartupObject>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Utilities\ClusterIdentificationUtility.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="ApplicationInsights.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ServiceFabric.Services" Version="6.0.1017" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FabricObserver.Extensibility\FabricObserver.Extensibility.csproj" />
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="PackageRoot\Data\Plugins\" />
</ItemGroup>
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,38 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="ClusterObserverPkg"
Version="2.2.2"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="ClusterObserverType" />
</ServiceTypes>
<!-- Code package is your service executable. -->
<CodePackage Name="Code" Version="2.2.2">
<EntryPoint>
<ExeHost>
<Program>ClusterObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="2.2.2" />
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<DataPackage Name="Data" Version="2.2.2" />
<Resources>
<Endpoints>
<!-- This endpoint is used by the communication listener to obtain the port on which to
listen. Please note that if your service is partitioned, this port is shared with
replicas of different partitions that are placed in your code. -->
<Endpoint Name="ServiceEndpoint" />
</Endpoints>
</Resources>
</ServiceManifest>
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="ClusterObserverPkg"
Version="2.2.3"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="ClusterObserverType" />
</ServiceTypes>
<!-- Code package is your service executable. -->
<CodePackage Name="Code" Version="2.2.3">
<EntryPoint>
<ExeHost>
<Program>ClusterObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="2.2.3" />
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<DataPackage Name="Data" Version="2.2.3" />
<Resources>
<Endpoints>
<!-- This endpoint is used by the communication listener to obtain the port on which to
listen. Please note that if your service is partitioned, this port is shared with
replicas of different partitions that are placed in your code. -->
<Endpoint Name="ServiceEndpoint" />
</Endpoints>
</Resources>
</ServiceManifest>

Просмотреть файл

@ -1,264 +1,264 @@
### ClusterObserver 2.2.2
#### This version - and all subsequent versions - requires SF Runtime >= 9.0 and targets .NET 6
ClusterObserver (CO) is a stateless singleton Service Fabric .NET 6 service that runs on one node in a cluster. CO observes cluster health (aggregated)
and sends telemetry when a cluster is in Error or Warning. CO shares a very small subset of FabricObserver's (FO) code. It is designed to be completely independent from FO sources,
but lives in this repo (and SLN) because it is very useful to have both services deployed, especially for those who want cluster-level health observation and reporting in addition to
the node-level user-defined resource monitoring, health event creation, and health reporting done by FO. FabricObserver is designed to generate Service Fabric health events based on user-defined resource usage Warning and Error thresholds which ClusterObserver sends to your log analytics and alerting service.
By design, CO will send an Ok health state report when a cluster goes from Warning or Error state to Ok.
CO only sends telemetry when something is wrong or when something that was previously wrong recovers. This limits the amount of data sent to your log analytics service. Like FabricObserver, you can implement whatever analytics backend
you want by implementing the IObserverTelemetryProvider interface. As stated, this is already implemented for both Azure ApplicationInsights and Azure LogAnalytics.
The core idea is that you use the aggregated cluster error/warning/Ok health state information from ClusterObserver to fire alerts and/or trigger some other action that gets your attention and/or some SF on-call's enagement via auto-creating a support incident (and an Ok signal would mean auto-mitigate the related incident/ticket).
```As of version 2.2.0.831/960, ClusterObserver supports the FabricObserver extensibility model. This means you can extend the behavior of ClusterObserver by writing your own observer plugins just as you can do with FabricObserver.```
[FabricObserver plugin documentation](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md) applies to ClusterObserver as well. The difference, of course, is that you will copy your plugin dll and its dependencies into ClusterObserver\PackageRoot\Data folder.
You can change ClusterObserver configuration parameters by doing a versionless Application Parameter Upgrade. This means you can change settings for ClusterObserver without having to redeploy the application or any packages.
Application Parameter Upgrade Example:
* Open an Admin Powershell console.
* Connect to your Service Fabric cluster using Connect-ServiceFabricCluster command.
* Create a variable that contains all the settings you want update:
```Powershell
$appParams = @{ "RunInterval" = "00:10:00"; "MaxTimeNodeStatusNotOk" = "04:00:00"; }
```
Then execute the application upgrade with
```Powershell
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/ClusterObserver -ApplicationTypeVersion 2.2.0.960 -ApplicationParameter $appParams -Monitored -FailureAction rollback
```
### ClusterObserver Configuration
#### Settings.xml:
```XML
<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Section Name="ObserverManagerConfiguration">
<!-- Required: Amount of time, in seconds, to sleep before the next iteration of clusterobserver run loop. Internally, the run loop will sleep for 15 seconds if this
setting is not greater than 0. -->
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="" MustOverride="true" />
<!-- Required: Amount of time, in seconds, ClusterObserver is allowed to complete a run. If this time is exceeded,
then the offending observer will be marked as broken and will not run again.
Below setting represents 60 minutes. -->
<Parameter Name="ObserverExecutionTimeout" Value="" MustOverride="true" />
<!-- Required: Location on disk to store observer data, including ObserverManager.
ClusterObserver will write to its own directory on this path.
**NOTE: For Linux runtime target, just supply the name of the directory (not a path with drive letter like you for Windows).** -->
<Parameter Name="ObserverLogPath" Value="" MustOverride="true" />
<!-- Required: Enabling this will generate noisy logs. Disabling it means only Warning and Error information
will be locally logged. This is the recommended setting. Note that file logging is generally
only useful for FabricObserverWebApi, which is an optional log reader service that ships in this repo. -->
<Parameter Name="EnableVerboseLogging" Value="" MustOverride="true" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="" MustOverride="true" />
<Parameter Name="EnableETWProvider" Value="" MustOverride="true" />
<Parameter Name="ETWProviderName" Value="" MustOverride="true" />
<Parameter Name="EnableTelemetryProvider" Value="" MustOverride="true" />
<Parameter Name="EnableOperationalTelemetry" Value="" MustOverride="true" />
<!-- Non-overridable. -->
<Parameter Name="AsyncOperationTimeoutSeconds" Value="120" />
<!-- Required: Supported Values are AzureApplicationInsights or AzureLogAnalytics as these providers are implemented. -->
<Parameter Name="TelemetryProvider" Value="AzureLogAnalytics" />
<!-- AzureApplicationInsights -->
<!-- OBSOLETE: Use AppInsightsConnectionString instead. Setting this has no effect. -->
<Parameter Name="AppInsightsInstrumentationKey" Value="" />
<!-- Required-If TelemetryProvider is AzureApplicationInsights. Your Connection String. -->
<Parameter Name="AppInsightsConnectionString" Value="" />
<!-- AzureLogAnalytics -->
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Your Workspace Id. -->
<Parameter Name="LogAnalyticsWorkspaceId" Value="" />
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Your Shared Key. -->
<Parameter Name="LogAnalyticsSharedKey" Value="" />
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Log scope. Default is Application. -->
<Parameter Name="LogAnalyticsLogType" Value="ClusterObserver" />
<!-- Optional: Amount of time in seconds to wait before ObserverManager signals shutdown. -->
<Parameter Name="ObserverShutdownGracePeriodInSeconds" Value="1" />
</Section>
<!-- ClusterObserver Configuration Settings. NOTE: These are overridable settings, see ApplicationManifest.xml.
The Values for these will be overriden by ApplicationManifest Parameter settings. Set DefaultValue for each
overridable parameter in that file, not here, as the parameter DefaultValues in ApplicationManifest.xml will be used, by default.
This design is to enable unversioned application-parameter-only updates. This means you will be able to change
any of the MustOverride parameters below at runtime by doing an ApplicationUpdate with ApplicationParameters flag.
See: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-upgrade-advanced#upgrade-application-parameters-independently-of-version -->
<Section Name="ClusterObserverConfiguration">
<!-- Maximum amount of time to wait for an async operation to complete (e.g., any of the SF API calls..) -->
<Parameter Name="AsyncOperationTimeoutSeconds" Value="" MustOverride="true" />
<!-- Required: To enable or not enable, that is the question.-->
<Parameter Name="Enabled" Value="" MustOverride="true" />
<!-- Optional: Enabling this will generate noisy logs. Disabling it means only Warning and Error information
will be locally logged. This is the recommended setting. Note that file logging is generally
only useful for FabricObserverWebApi, which is an optional log reader service that ships in this repo. -->
<Parameter Name="EnableEtw" Value="" MustOverride="true"/>
<Parameter Name="EnableVerboseLogging" Value="" MustOverride="true" />
<Parameter Name="EnableTelemetry" Value="" MustOverride="true" />
<!-- Optional: Emit health details for both Warning and Error for aggregated cluster health?
Aggregated Error evaluations will always be transmitted regardless of this setting. -->
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="" MustOverride="true" />
<!-- Maximum amount of time a node can be in disabling/disabled/down state before
emitting a Warning signal.-->
<Parameter Name="MaxTimeNodeStatusNotOk" Value="" MustOverride="true" />
<!-- How often to run ClusterObserver. This is a Timespan value, e.g., 00:10:00 means every 10 minutes, for example. -->
<Parameter Name="RunInterval" Value="" MustOverride="true" />
<!-- Report on currently executing Repair Jobs in the cluster. -->
<Parameter Name="MonitorRepairJobs" Value="" MustOverride="true" />
<!-- Monitor Cluster and Application Upgrades. -->
<Parameter Name="MonitorUpgrades" Value="" MustOverride="true" />
</Section>
<!-- Plugin model sample. Just add the configuration info here that your observer needs.
**NOTE**: You must name these Sections in the following way: [ObserverName]Configuration.
Example: SampleNewObserverConfiguration, where SampleNewObserver is the type name of the observer plugin.
See the SampleObserverPlugin project for a complete example of implementing an observer plugin.
If you want to enable versionless parameter-only application upgrades, then add MustOverride to the Parameters you want to be
able to change without redeploying CO and add them to ApplicationManifest.xml just like for ClusterObserver.
<Section Name="MyClusterObserverPluginConfiguration">
<Parameter Name="Enabled" Value="true" />
<Parameter Name="ClusterOperationTimeoutSeconds" Value="120" />
<Parameter Name="EnableEtw" Value="false" />
<Parameter Name="EnableVerboseLogging" Value="false" />
<Parameter Name="RunInterval" Value="" />
</Section> -->
</Settings>
```
#### ApplicationManifest.xml:
``` XML
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ClusterObserverType" ApplicationTypeVersion="2.2.2" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<!-- ClusterObserverManager settings. -->
<Parameter Name="ObserverManagerObserverLoopSleepTimeSeconds" DefaultValue="30" />
<Parameter Name="ObserverManagerObserverExecutionTimeout" DefaultValue="3600" />
<Parameter Name="ObserverManagerEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="ObserverManagerEnableETWProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerETWProviderName" DefaultValue="ClusterObserverETWProvider" />
<Parameter Name="ObserverManagerEnableTelemetryProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="true" />
<Parameter Name="ObserverManagerObserverFailureHealthStateLevel" DefaultValue="Warning" />
<Parameter Name="ClusterObserverLogPath" DefaultValue="cluster_observer_logs" />
<!-- ClusterObserver settings. -->
<Parameter Name="ClusterObserverEnabled" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableETW" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableTelemetry" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="MaxTimeNodeStatusNotOk" DefaultValue="02:00:00" />
<Parameter Name="EmitHealthWarningEvaluationDetails" DefaultValue="true" />
<Parameter Name="ClusterObserverRunInterval" DefaultValue="" />
<Parameter Name="ClusterObserverAsyncOperationTimeoutSeconds" DefaultValue="120" />
<Parameter Name="MonitorRepairJobs" DefaultValue="true" />
<Parameter Name="MonitorUpgrades" DefaultValue="true" />
<!-- Plugin settings... -->
</Parameters>
<!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="ClusterObserverPkg" ServiceManifestVersion="2.2.2" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="ObserverManagerConfiguration">
<Parameter Name="EnableOperationalTelemetry" Value="[ObserverManagerEnableOperationalTelemetry]" />
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="[ObserverManagerObserverLoopSleepTimeSeconds]" />
<Parameter Name="ObserverExecutionTimeout" Value="[ObserverManagerObserverExecutionTimeout]" />
<Parameter Name="ObserverLogPath" Value="[ClusterObserverLogPath]" />
<Parameter Name="EnableVerboseLogging" Value="[ObserverManagerEnableVerboseLogging]" />
<Parameter Name="EnableETWProvider" Value="[ObserverManagerEnableETWProvider]" />
<Parameter Name="ETWProviderName" Value="[ObserverManagerETWProviderName]" />
<Parameter Name="EnableTelemetryProvider" Value="[ObserverManagerEnableTelemetryProvider]" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="[ObserverManagerObserverFailureHealthStateLevel]" />
</Section>
<Section Name="ClusterObserverConfiguration">
<Parameter Name="Enabled" Value="[ClusterObserverEnabled]" />
<Parameter Name="EnableEtw" Value="[ClusterObserverEnableETW]" />
<Parameter Name="EnableTelemetry" Value="[ClusterObserverEnableTelemetry]" />
<Parameter Name="EnableVerboseLogging" Value="[ClusterObserverEnableVerboseLogging]" />
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="[EmitHealthWarningEvaluationDetails]" />
<Parameter Name="MaxTimeNodeStatusNotOk" Value="[MaxTimeNodeStatusNotOk]" />
<Parameter Name="RunInterval" Value="[ClusterObserverRunInterval]" />
<Parameter Name="AsyncOperationTimeoutSeconds" Value="[ClusterObserverAsyncOperationTimeoutSeconds]" />
<Parameter Name="MonitorRepairJobs" Value="[MonitorRepairJobs]" />
<Parameter Name="MonitorUpgrades" Value="[MonitorUpgrades]" />
</Section>
<!-- Plugin sections.. -->
</Settings>
</ConfigOverride>
</ConfigOverrides>
</ServiceManifestImport>
</ApplicationManifest>
```
Example LogAnalytics Query
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/COQueryFileHandles.png "Example LogAnalytics query")
You should configure FabricObserver to monitor ClusterObserver, of course. :)
## Operational Telemetry
ClusterObserver operational data is transmitted to Microsoft and contains information about ClusterObserver.
**This information is only used by the Service Fabric team and will be retained for no more than 90 days.**
Disabling / Enabling transmission of Operational Data:
Transmission of operational data is controlled by a setting and can be easily turned off. ```EnableOperationalTelemetry``` setting in ```ApplicationManifest.xml``` controls transmission of Operational data.
Setting the value to false as below will immediately stop the transmission of operational data:
**\<Parameter Name="EnableOperationalTelemetry" DefaultValue="false" />**
#### Questions we want to answer from data:
- CO started successfully.
- Health of CO
- If CO crashes with an unhandled exception that can be caught, related error information will be sent to us (this will include the offending FO stack). This will help us improve quality.
- This telemetry is sent only once, after the deployed CO instance starts monitoring.
#### Operational data details:
Here is a full example of exactly what is sent in one of these telemetry events, in this case, from an SFRP cluster:
```JSON
{
"EventName": "OperationalEvent",
"TaskName": "ClusterObserver",
"ClusterId": "00000000-1111-1111-0000-00f00d000d",
"ClusterType": "SFRP",
"COVersion": "2.2.0.960",
"Timestamp": "2022-07-12T19:02:04.4287671Z",
"OS": "Windows"
}
```
Let's take a look at the data and why we think it is useful to share with us. We'll go through each object property in the JSON above.
- **EventName** - this is the name of the telemetry event.
- **TaskName** - this specifies that the event is from ClusterObserver.
- **ClusterId** - this is used to both uniquely identify a telemetry event and to correlate data that comes from a cluster.
- **ClusterType** - this is the type of cluster: Standalone, SFRP or undefined.
- **COVersion** - this is the internal version of CO (if you have your own version naming, we will only know what the CO code version is (not your specific CO app version name)).
- **Timestamp** - this is the time, in UTC, when CO sent the telemetry.
- **OS** - this is the operating system CO is running on (Windows or Linux).
If the ClusterType is not SFRP then a TenantId (Guid) is sent for use in the same way we use ClusterId.
We would greatly appreciate you sharing this information with us!
### ClusterObserver 2.2.3
#### This version - and all subsequent versions - requires SF Runtime >= 9.0 and targets .NET 6
ClusterObserver (CO) is a stateless singleton Service Fabric .NET 6 service that runs on one node in a cluster. CO observes cluster health (aggregated)
and sends telemetry when a cluster is in Error or Warning. CO shares a very small subset of FabricObserver's (FO) code. It is designed to be completely independent from FO sources,
but lives in this repo (and SLN) because it is very useful to have both services deployed, especially for those who want cluster-level health observation and reporting in addition to
the node-level user-defined resource monitoring, health event creation, and health reporting done by FO. FabricObserver is designed to generate Service Fabric health events based on user-defined resource usage Warning and Error thresholds which ClusterObserver sends to your log analytics and alerting service.
By design, CO will send an Ok health state report when a cluster goes from Warning or Error state to Ok.
CO only sends telemetry when something is wrong or when something that was previously wrong recovers. This limits the amount of data sent to your log analytics service. Like FabricObserver, you can implement whatever analytics backend
you want by implementing the IObserverTelemetryProvider interface. As stated, this is already implemented for both Azure ApplicationInsights and Azure LogAnalytics.
The core idea is that you use the aggregated cluster error/warning/Ok health state information from ClusterObserver to fire alerts and/or trigger some other action that gets your attention and/or some SF on-call's enagement via auto-creating a support incident (and an Ok signal would mean auto-mitigate the related incident/ticket).
```As of version 2.2.0.831/960, ClusterObserver supports the FabricObserver extensibility model. This means you can extend the behavior of ClusterObserver by writing your own observer plugins just as you can do with FabricObserver.```
[FabricObserver plugin documentation](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md) applies to ClusterObserver as well. The difference, of course, is that you will copy your plugin dll and its dependencies into ClusterObserver\PackageRoot\Data folder.
You can change ClusterObserver configuration parameters by doing a versionless Application Parameter Upgrade. This means you can change settings for ClusterObserver without having to redeploy the application or any packages.
Application Parameter Upgrade Example:
* Open an Admin Powershell console.
* Connect to your Service Fabric cluster using Connect-ServiceFabricCluster command.
* Create a variable that contains all the settings you want update:
```Powershell
$appParams = @{ "RunInterval" = "00:10:00"; "MaxTimeNodeStatusNotOk" = "04:00:00"; }
```
Then execute the application upgrade with
```Powershell
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/ClusterObserver -ApplicationTypeVersion 2.2.0.960 -ApplicationParameter $appParams -Monitored -FailureAction rollback
```
### ClusterObserver Configuration
#### Settings.xml:
```XML
<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Section Name="ObserverManagerConfiguration">
<!-- Required: Amount of time, in seconds, to sleep before the next iteration of clusterobserver run loop. Internally, the run loop will sleep for 15 seconds if this
setting is not greater than 0. -->
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="" MustOverride="true" />
<!-- Required: Amount of time, in seconds, ClusterObserver is allowed to complete a run. If this time is exceeded,
then the offending observer will be marked as broken and will not run again.
Below setting represents 60 minutes. -->
<Parameter Name="ObserverExecutionTimeout" Value="" MustOverride="true" />
<!-- Required: Location on disk to store observer data, including ObserverManager.
ClusterObserver will write to its own directory on this path.
**NOTE: For Linux runtime target, just supply the name of the directory (not a path with drive letter like you for Windows).** -->
<Parameter Name="ObserverLogPath" Value="" MustOverride="true" />
<!-- Required: Enabling this will generate noisy logs. Disabling it means only Warning and Error information
will be locally logged. This is the recommended setting. Note that file logging is generally
only useful for FabricObserverWebApi, which is an optional log reader service that ships in this repo. -->
<Parameter Name="EnableVerboseLogging" Value="" MustOverride="true" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="" MustOverride="true" />
<Parameter Name="EnableETWProvider" Value="" MustOverride="true" />
<Parameter Name="ETWProviderName" Value="" MustOverride="true" />
<Parameter Name="EnableTelemetryProvider" Value="" MustOverride="true" />
<Parameter Name="EnableOperationalTelemetry" Value="" MustOverride="true" />
<!-- Non-overridable. -->
<Parameter Name="AsyncOperationTimeoutSeconds" Value="120" />
<!-- Required: Supported Values are AzureApplicationInsights or AzureLogAnalytics as these providers are implemented. -->
<Parameter Name="TelemetryProvider" Value="AzureLogAnalytics" />
<!-- AzureApplicationInsights -->
<!-- OBSOLETE: Use AppInsightsConnectionString instead. Setting this has no effect. -->
<Parameter Name="AppInsightsInstrumentationKey" Value="" />
<!-- Required-If TelemetryProvider is AzureApplicationInsights. Your Connection String. -->
<Parameter Name="AppInsightsConnectionString" Value="" />
<!-- AzureLogAnalytics -->
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Your Workspace Id. -->
<Parameter Name="LogAnalyticsWorkspaceId" Value="" />
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Your Shared Key. -->
<Parameter Name="LogAnalyticsSharedKey" Value="" />
<!-- Required-If TelemetryProvider is AzureLogAnalytics. Log scope. Default is Application. -->
<Parameter Name="LogAnalyticsLogType" Value="ClusterObserver" />
<!-- Optional: Amount of time in seconds to wait before ObserverManager signals shutdown. -->
<Parameter Name="ObserverShutdownGracePeriodInSeconds" Value="1" />
</Section>
<!-- ClusterObserver Configuration Settings. NOTE: These are overridable settings, see ApplicationManifest.xml.
The Values for these will be overriden by ApplicationManifest Parameter settings. Set DefaultValue for each
overridable parameter in that file, not here, as the parameter DefaultValues in ApplicationManifest.xml will be used, by default.
This design is to enable unversioned application-parameter-only updates. This means you will be able to change
any of the MustOverride parameters below at runtime by doing an ApplicationUpdate with ApplicationParameters flag.
See: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-upgrade-advanced#upgrade-application-parameters-independently-of-version -->
<Section Name="ClusterObserverConfiguration">
<!-- Maximum amount of time to wait for an async operation to complete (e.g., any of the SF API calls..) -->
<Parameter Name="AsyncOperationTimeoutSeconds" Value="" MustOverride="true" />
<!-- Required: To enable or not enable, that is the question.-->
<Parameter Name="Enabled" Value="" MustOverride="true" />
<!-- Optional: Enabling this will generate noisy logs. Disabling it means only Warning and Error information
will be locally logged. This is the recommended setting. Note that file logging is generally
only useful for FabricObserverWebApi, which is an optional log reader service that ships in this repo. -->
<Parameter Name="EnableEtw" Value="" MustOverride="true"/>
<Parameter Name="EnableVerboseLogging" Value="" MustOverride="true" />
<Parameter Name="EnableTelemetry" Value="" MustOverride="true" />
<!-- Optional: Emit health details for both Warning and Error for aggregated cluster health?
Aggregated Error evaluations will always be transmitted regardless of this setting. -->
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="" MustOverride="true" />
<!-- Maximum amount of time a node can be in disabling/disabled/down state before
emitting a Warning signal.-->
<Parameter Name="MaxTimeNodeStatusNotOk" Value="" MustOverride="true" />
<!-- How often to run ClusterObserver. This is a Timespan value, e.g., 00:10:00 means every 10 minutes, for example. -->
<Parameter Name="RunInterval" Value="" MustOverride="true" />
<!-- Report on currently executing Repair Jobs in the cluster. -->
<Parameter Name="MonitorRepairJobs" Value="" MustOverride="true" />
<!-- Monitor Cluster and Application Upgrades. -->
<Parameter Name="MonitorUpgrades" Value="" MustOverride="true" />
</Section>
<!-- Plugin model sample. Just add the configuration info here that your observer needs.
**NOTE**: You must name these Sections in the following way: [ObserverName]Configuration.
Example: SampleNewObserverConfiguration, where SampleNewObserver is the type name of the observer plugin.
See the SampleObserverPlugin project for a complete example of implementing an observer plugin.
If you want to enable versionless parameter-only application upgrades, then add MustOverride to the Parameters you want to be
able to change without redeploying CO and add them to ApplicationManifest.xml just like for ClusterObserver.
<Section Name="MyClusterObserverPluginConfiguration">
<Parameter Name="Enabled" Value="true" />
<Parameter Name="ClusterOperationTimeoutSeconds" Value="120" />
<Parameter Name="EnableEtw" Value="false" />
<Parameter Name="EnableVerboseLogging" Value="false" />
<Parameter Name="RunInterval" Value="" />
</Section> -->
</Settings>
```
#### ApplicationManifest.xml:
``` XML
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ClusterObserverType" ApplicationTypeVersion="2.2.3" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<!-- ClusterObserverManager settings. -->
<Parameter Name="ObserverManagerObserverLoopSleepTimeSeconds" DefaultValue="30" />
<Parameter Name="ObserverManagerObserverExecutionTimeout" DefaultValue="3600" />
<Parameter Name="ObserverManagerEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="ObserverManagerEnableETWProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerETWProviderName" DefaultValue="ClusterObserverETWProvider" />
<Parameter Name="ObserverManagerEnableTelemetryProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="true" />
<Parameter Name="ObserverManagerObserverFailureHealthStateLevel" DefaultValue="Warning" />
<Parameter Name="ClusterObserverLogPath" DefaultValue="cluster_observer_logs" />
<!-- ClusterObserver settings. -->
<Parameter Name="ClusterObserverEnabled" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableETW" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableTelemetry" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="MaxTimeNodeStatusNotOk" DefaultValue="02:00:00" />
<Parameter Name="EmitHealthWarningEvaluationDetails" DefaultValue="true" />
<Parameter Name="ClusterObserverRunInterval" DefaultValue="" />
<Parameter Name="ClusterObserverAsyncOperationTimeoutSeconds" DefaultValue="120" />
<Parameter Name="MonitorRepairJobs" DefaultValue="true" />
<Parameter Name="MonitorUpgrades" DefaultValue="true" />
<!-- Plugin settings... -->
</Parameters>
<!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="ClusterObserverPkg" ServiceManifestVersion="2.2.3" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="ObserverManagerConfiguration">
<Parameter Name="EnableOperationalTelemetry" Value="[ObserverManagerEnableOperationalTelemetry]" />
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="[ObserverManagerObserverLoopSleepTimeSeconds]" />
<Parameter Name="ObserverExecutionTimeout" Value="[ObserverManagerObserverExecutionTimeout]" />
<Parameter Name="ObserverLogPath" Value="[ClusterObserverLogPath]" />
<Parameter Name="EnableVerboseLogging" Value="[ObserverManagerEnableVerboseLogging]" />
<Parameter Name="EnableETWProvider" Value="[ObserverManagerEnableETWProvider]" />
<Parameter Name="ETWProviderName" Value="[ObserverManagerETWProviderName]" />
<Parameter Name="EnableTelemetryProvider" Value="[ObserverManagerEnableTelemetryProvider]" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="[ObserverManagerObserverFailureHealthStateLevel]" />
</Section>
<Section Name="ClusterObserverConfiguration">
<Parameter Name="Enabled" Value="[ClusterObserverEnabled]" />
<Parameter Name="EnableEtw" Value="[ClusterObserverEnableETW]" />
<Parameter Name="EnableTelemetry" Value="[ClusterObserverEnableTelemetry]" />
<Parameter Name="EnableVerboseLogging" Value="[ClusterObserverEnableVerboseLogging]" />
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="[EmitHealthWarningEvaluationDetails]" />
<Parameter Name="MaxTimeNodeStatusNotOk" Value="[MaxTimeNodeStatusNotOk]" />
<Parameter Name="RunInterval" Value="[ClusterObserverRunInterval]" />
<Parameter Name="AsyncOperationTimeoutSeconds" Value="[ClusterObserverAsyncOperationTimeoutSeconds]" />
<Parameter Name="MonitorRepairJobs" Value="[MonitorRepairJobs]" />
<Parameter Name="MonitorUpgrades" Value="[MonitorUpgrades]" />
</Section>
<!-- Plugin sections.. -->
</Settings>
</ConfigOverride>
</ConfigOverrides>
</ServiceManifestImport>
</ApplicationManifest>
```
Example LogAnalytics Query
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/COQueryFileHandles.png "Example LogAnalytics query")
You should configure FabricObserver to monitor ClusterObserver, of course. :)
## Operational Telemetry
ClusterObserver operational data is transmitted to Microsoft and contains information about ClusterObserver.
**This information is only used by the Service Fabric team and will be retained for no more than 90 days.**
Disabling / Enabling transmission of Operational Data:
Transmission of operational data is controlled by a setting and can be easily turned off. ```EnableOperationalTelemetry``` setting in ```ApplicationManifest.xml``` controls transmission of Operational data.
Setting the value to false as below will immediately stop the transmission of operational data:
**\<Parameter Name="EnableOperationalTelemetry" DefaultValue="false" />**
#### Questions we want to answer from data:
- CO started successfully.
- Health of CO
- If CO crashes with an unhandled exception that can be caught, related error information will be sent to us (this will include the offending FO stack). This will help us improve quality.
- This telemetry is sent only once, after the deployed CO instance starts monitoring.
#### Operational data details:
Here is a full example of exactly what is sent in one of these telemetry events, in this case, from an SFRP cluster:
```JSON
{
"EventName": "OperationalEvent",
"TaskName": "ClusterObserver",
"ClusterId": "00000000-1111-1111-0000-00f00d000d",
"ClusterType": "SFRP",
"COVersion": "2.2.0.960",
"Timestamp": "2022-07-12T19:02:04.4287671Z",
"OS": "Windows"
}
```
Let's take a look at the data and why we think it is useful to share with us. We'll go through each object property in the JSON above.
- **EventName** - this is the name of the telemetry event.
- **TaskName** - this specifies that the event is from ClusterObserver.
- **ClusterId** - this is used to both uniquely identify a telemetry event and to correlate data that comes from a cluster.
- **ClusterType** - this is the type of cluster: Standalone, SFRP or undefined.
- **COVersion** - this is the internal version of CO (if you have your own version naming, we will only know what the CO code version is (not your specific CO app version name)).
- **Timestamp** - this is the time, in UTC, when CO sent the telemetry.
- **OS** - this is the operating system CO is running on (Windows or Linux).
If the ClusterType is not SFRP then a TenantId (Guid) is sent for use in the same way we use ClusterId.
We would greatly appreciate you sharing this information with us!

Просмотреть файл

@ -1,63 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ClusterObserverType" ApplicationTypeVersion="2.2.2" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<!-- ClusterObserverManager settings. -->
<Parameter Name="ObserverManagerObserverLoopSleepTimeSeconds" DefaultValue="30" />
<Parameter Name="ObserverManagerObserverExecutionTimeout" DefaultValue="3600" />
<Parameter Name="ObserverManagerEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="ObserverManagerEnableETWProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerETWProviderName" DefaultValue="ClusterObserverETWProvider" />
<Parameter Name="ObserverManagerEnableTelemetryProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="true" />
<Parameter Name="ObserverManagerObserverFailureHealthStateLevel" DefaultValue="Warning" />
<Parameter Name="ClusterObserverLogPath" DefaultValue="cluster_observer_logs" />
<!-- ClusterObserver settings. -->
<Parameter Name="ClusterObserverEnabled" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableETW" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableTelemetry" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="MaxTimeNodeStatusNotOk" DefaultValue="02:00:00" />
<Parameter Name="EmitHealthWarningEvaluationDetails" DefaultValue="true" />
<Parameter Name="ClusterObserverRunInterval" DefaultValue="" />
<Parameter Name="ClusterObserverAsyncOperationTimeoutSeconds" DefaultValue="120" />
<Parameter Name="MonitorRepairJobs" DefaultValue="true" />
<Parameter Name="MonitorUpgrades" DefaultValue="true" />
<!-- Plugin settings... -->
</Parameters>
<!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="ClusterObserverPkg" ServiceManifestVersion="2.2.2" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="ObserverManagerConfiguration">
<Parameter Name="EnableOperationalTelemetry" Value="[ObserverManagerEnableOperationalTelemetry]" />
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="[ObserverManagerObserverLoopSleepTimeSeconds]" />
<Parameter Name="ObserverExecutionTimeout" Value="[ObserverManagerObserverExecutionTimeout]" />
<Parameter Name="ObserverLogPath" Value="[ClusterObserverLogPath]" />
<Parameter Name="EnableVerboseLogging" Value="[ObserverManagerEnableVerboseLogging]" />
<Parameter Name="EnableETWProvider" Value="[ObserverManagerEnableETWProvider]" />
<Parameter Name="ETWProviderName" Value="[ObserverManagerETWProviderName]" />
<Parameter Name="EnableTelemetryProvider" Value="[ObserverManagerEnableTelemetryProvider]" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="[ObserverManagerObserverFailureHealthStateLevel]" />
</Section>
<Section Name="ClusterObserverConfiguration">
<Parameter Name="Enabled" Value="[ClusterObserverEnabled]" />
<Parameter Name="EnableEtw" Value="[ClusterObserverEnableETW]" />
<Parameter Name="EnableTelemetry" Value="[ClusterObserverEnableTelemetry]" />
<Parameter Name="EnableVerboseLogging" Value="[ClusterObserverEnableVerboseLogging]" />
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="[EmitHealthWarningEvaluationDetails]" />
<Parameter Name="MaxTimeNodeStatusNotOk" Value="[MaxTimeNodeStatusNotOk]" />
<Parameter Name="RunInterval" Value="[ClusterObserverRunInterval]" />
<Parameter Name="AsyncOperationTimeoutSeconds" Value="[ClusterObserverAsyncOperationTimeoutSeconds]" />
<Parameter Name="MonitorRepairJobs" Value="[MonitorRepairJobs]" />
<Parameter Name="MonitorUpgrades" Value="[MonitorUpgrades]" />
</Section>
<!-- Plugin sections.. -->
</Settings>
</ConfigOverride>
</ConfigOverrides>
</ServiceManifestImport>
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ClusterObserverType" ApplicationTypeVersion="2.2.3" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<!-- ClusterObserverManager settings. -->
<Parameter Name="ObserverManagerObserverLoopSleepTimeSeconds" DefaultValue="30" />
<Parameter Name="ObserverManagerObserverExecutionTimeout" DefaultValue="3600" />
<Parameter Name="ObserverManagerEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="ObserverManagerEnableETWProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerETWProviderName" DefaultValue="ClusterObserverETWProvider" />
<Parameter Name="ObserverManagerEnableTelemetryProvider" DefaultValue="true" />
<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="true" />
<Parameter Name="ObserverManagerObserverFailureHealthStateLevel" DefaultValue="Warning" />
<Parameter Name="ClusterObserverLogPath" DefaultValue="cluster_observer_logs" />
<!-- ClusterObserver settings. -->
<Parameter Name="ClusterObserverEnabled" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableETW" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableTelemetry" DefaultValue="true" />
<Parameter Name="ClusterObserverEnableVerboseLogging" DefaultValue="false" />
<Parameter Name="MaxTimeNodeStatusNotOk" DefaultValue="02:00:00" />
<Parameter Name="EmitHealthWarningEvaluationDetails" DefaultValue="true" />
<Parameter Name="ClusterObserverRunInterval" DefaultValue="" />
<Parameter Name="ClusterObserverAsyncOperationTimeoutSeconds" DefaultValue="120" />
<Parameter Name="MonitorRepairJobs" DefaultValue="true" />
<Parameter Name="MonitorUpgrades" DefaultValue="true" />
<!-- Plugin settings... -->
</Parameters>
<!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="ClusterObserverPkg" ServiceManifestVersion="2.2.3" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="ObserverManagerConfiguration">
<Parameter Name="EnableOperationalTelemetry" Value="[ObserverManagerEnableOperationalTelemetry]" />
<Parameter Name="ObserverLoopSleepTimeSeconds" Value="[ObserverManagerObserverLoopSleepTimeSeconds]" />
<Parameter Name="ObserverExecutionTimeout" Value="[ObserverManagerObserverExecutionTimeout]" />
<Parameter Name="ObserverLogPath" Value="[ClusterObserverLogPath]" />
<Parameter Name="EnableVerboseLogging" Value="[ObserverManagerEnableVerboseLogging]" />
<Parameter Name="EnableETWProvider" Value="[ObserverManagerEnableETWProvider]" />
<Parameter Name="ETWProviderName" Value="[ObserverManagerETWProviderName]" />
<Parameter Name="EnableTelemetryProvider" Value="[ObserverManagerEnableTelemetryProvider]" />
<Parameter Name="ObserverFailureHealthStateLevel" Value="[ObserverManagerObserverFailureHealthStateLevel]" />
</Section>
<Section Name="ClusterObserverConfiguration">
<Parameter Name="Enabled" Value="[ClusterObserverEnabled]" />
<Parameter Name="EnableEtw" Value="[ClusterObserverEnableETW]" />
<Parameter Name="EnableTelemetry" Value="[ClusterObserverEnableTelemetry]" />
<Parameter Name="EnableVerboseLogging" Value="[ClusterObserverEnableVerboseLogging]" />
<Parameter Name="EmitHealthWarningEvaluationDetails" Value="[EmitHealthWarningEvaluationDetails]" />
<Parameter Name="MaxTimeNodeStatusNotOk" Value="[MaxTimeNodeStatusNotOk]" />
<Parameter Name="RunInterval" Value="[ClusterObserverRunInterval]" />
<Parameter Name="AsyncOperationTimeoutSeconds" Value="[ClusterObserverAsyncOperationTimeoutSeconds]" />
<Parameter Name="MonitorRepairJobs" Value="[MonitorRepairJobs]" />
<Parameter Name="MonitorUpgrades" Value="[MonitorUpgrades]" />
</Section>
<!-- Plugin sections.. -->
</Settings>
</ConfigOverride>
</ConfigOverrides>
</ServiceManifestImport>
</ApplicationManifest>

Просмотреть файл

@ -1,117 +1,117 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The Service Fabric cluster resource name from the Azure resource group. Example: servicefabriccluster123"
}
},
"applicationTypeVersionClusterObserver": {
"type": "string",
"defaultValue": "2.2.2",
"metadata": {
"description": "Provide the app version number of ClusterObserver. This must be identical to the version specified in the corresponding sfpkg."
}
},
"packageUrlClusterObserver": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "This has to be a public accessible URL for the sfpkg file which contains the ClusterObserver app package. Example: https://github.com/microsoft/service-fabric-observer/releases/download/57648098/Microsoft.ServiceFabricApps.ClusterObserver.Windows.SelfContained.2.2.0.960.sfpkg"
}
}
},
"variables": {
"applicationTypeNameClusterObserver": "ClusterObserverType",
"applicationNameClusterObserver": "ClusterObserver",
"serviceNameClusterObserver": "[concat(variables('applicationNameClusterObserver'), '~ClusterObserverService')]",
"serviceTypeNameClusterObserver": "ClusterObserverType",
"sfrpApiVersion": "2021-06-01"
},
"resources": [
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"properties": {
"provisioningState": "Default"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes/versions",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameClusterObserver'), '/', parameters('applicationTypeVersionClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"appPackageUrl": "[parameters('packageUrlClusterObserver')]"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameClusterObserver'), '/versions/', parameters('applicationTypeVersionClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"typeName": "[variables('applicationTypeNameClusterObserver')]",
"typeVersion": "[parameters('applicationTypeVersionClusterObserver')]",
"parameters": {
"MonitorRepairJobs": "true",
"ClusterObserverRunInterval": "00:15:00"
},
"upgradePolicy": {
"upgradeReplicaSetCheckTimeout": "01:00:00.0",
"forceRestart": "false",
"rollingUpgradeMonitoringPolicy": {
"healthCheckWaitDuration": "00:02:00.0",
"healthCheckStableDuration": "00:05:00.0",
"healthCheckRetryTimeout": "00:10:00.0",
"upgradeTimeout": "01:00:00.0",
"upgradeDomainTimeout": "00:20:00.0"
},
"applicationHealthPolicy": {
"considerWarningAsError": "false",
"maxPercentUnhealthyDeployedApplications": "50",
"defaultServiceTypeHealthPolicy": {
"maxPercentUnhealthyServices": "50",
"maxPercentUnhealthyPartitionsPerService": "50",
"maxPercentUnhealthyReplicasPerPartition": "50"
}
}
}
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications/services",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameClusterObserver'), '/', variables('serviceNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationNameClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"serviceKind": "Stateless",
"serviceTypeName": "[variables('serviceTypeNameClusterObserver')]",
"instanceCount": "1",
"partitionDescription": {
"partitionScheme": "Singleton"
},
"correlationScheme": [],
"serviceLoadMetrics": [],
"servicePlacementPolicies": []
}
}
]
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The Service Fabric cluster resource name from the Azure resource group. Example: servicefabriccluster123"
}
},
"applicationTypeVersionClusterObserver": {
"type": "string",
"defaultValue": "2.2.3",
"metadata": {
"description": "Provide the app version number of ClusterObserver. This must be identical to the version specified in the corresponding sfpkg."
}
},
"packageUrlClusterObserver": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "This has to be a public accessible URL for the sfpkg file which contains the ClusterObserver app package. Example: https://github.com/microsoft/service-fabric-observer/releases/download/57648098/Microsoft.ServiceFabricApps.ClusterObserver.Windows.SelfContained.2.2.0.960.sfpkg"
}
}
},
"variables": {
"applicationTypeNameClusterObserver": "ClusterObserverType",
"applicationNameClusterObserver": "ClusterObserver",
"serviceNameClusterObserver": "[concat(variables('applicationNameClusterObserver'), '~ClusterObserverService')]",
"serviceTypeNameClusterObserver": "ClusterObserverType",
"sfrpApiVersion": "2021-06-01"
},
"resources": [
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"properties": {
"provisioningState": "Default"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes/versions",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameClusterObserver'), '/', parameters('applicationTypeVersionClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"appPackageUrl": "[parameters('packageUrlClusterObserver')]"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameClusterObserver'), '/versions/', parameters('applicationTypeVersionClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"typeName": "[variables('applicationTypeNameClusterObserver')]",
"typeVersion": "[parameters('applicationTypeVersionClusterObserver')]",
"parameters": {
"MonitorRepairJobs": "true",
"ClusterObserverRunInterval": "00:15:00"
},
"upgradePolicy": {
"upgradeReplicaSetCheckTimeout": "01:00:00.0",
"forceRestart": "false",
"rollingUpgradeMonitoringPolicy": {
"healthCheckWaitDuration": "00:02:00.0",
"healthCheckStableDuration": "00:05:00.0",
"healthCheckRetryTimeout": "00:10:00.0",
"upgradeTimeout": "01:00:00.0",
"upgradeDomainTimeout": "00:20:00.0"
},
"applicationHealthPolicy": {
"considerWarningAsError": "false",
"maxPercentUnhealthyDeployedApplications": "50",
"defaultServiceTypeHealthPolicy": {
"maxPercentUnhealthyServices": "50",
"maxPercentUnhealthyPartitionsPerService": "50",
"maxPercentUnhealthyReplicasPerPartition": "50"
}
}
}
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications/services",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameClusterObserver'), '/', variables('serviceNameClusterObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationNameClusterObserver'))]"
],
"properties": {
"provisioningState": "Default",
"serviceKind": "Stateless",
"serviceTypeName": "[variables('serviceTypeNameClusterObserver')]",
"instanceCount": "1",
"partitionDescription": {
"partitionScheme": "Singleton"
},
"correlationScheme": [],
"serviceLoadMetrics": [],
"servicePlacementPolicies": []
}
}
]
}

Просмотреть файл

@ -1,15 +1,15 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"value": "<ClusterResourceName>"
},
"applicationTypeVersionClusterObserver": {
"value": "2.2.2"
},
"packageUrlClusterObserver": {
"value": "<PUBLIC-ACCESSIBLE-URL-FOR-CLUSTEROBSERVER-SFPKG>"
}
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"value": "<ClusterResourceName>"
},
"applicationTypeVersionClusterObserver": {
"value": "2.2.2"
},
"packageUrlClusterObserver": {
"value": "<PUBLIC-ACCESSIBLE-URL-FOR-CLUSTEROBSERVER-SFPKG>"
}
}
}

Просмотреть файл

@ -1,117 +1,117 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The Service Fabric cluster resource name from the Azure resource group. Example: servicefabriccluster123"
}
},
"applicationTypeVersionFabricObserver": {
"type": "string",
"defaultValue": "3.2.5",
"metadata": {
"description": "Provide the app version number of FabricObserver. This must be identical to the version, 3.2.5, in the referenced sfpkg specified in packageUrlFabricObserver."
}
},
"packageUrlFabricObserver": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "This has to be a public accessible URL for the sfpkg file which contains the FabricObserver app package. Example: https://github.com/microsoft/service-fabric-observer/releases/download/[xxxxxxxx]/Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained.3.2.5.sfpkg"
}
}
},
"variables": {
"applicationTypeNameFabricObserver": "FabricObserverType",
"applicationNameFabricObserver": "FabricObserver",
"serviceNameFabricObserver": "[concat(variables('applicationNameFabricObserver'), '~FabricObserverService')]",
"serviceTypeNameFabricObserver": "FabricObserverType",
"sfrpApiVersion": "2021-06-01"
},
"resources": [
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"properties": {
"provisioningState": "Default"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes/versions",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameFabricObserver'), '/', parameters('applicationTypeVersionFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"appPackageUrl": "[parameters('packageUrlFabricObserver')]"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameFabricObserver'), '/versions/', parameters('applicationTypeVersionFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"typeName": "[variables('applicationTypeNameFabricObserver')]",
"typeVersion": "[parameters('applicationTypeVersionFabricObserver')]",
"parameters": {
"AppObserverEnableChildProcessMonitoring": "true",
"FabricSystemObserverEnabled": "true"
},
"upgradePolicy": {
"upgradeReplicaSetCheckTimeout": "01:00:00.0",
"forceRestart": "false",
"rollingUpgradeMonitoringPolicy": {
"healthCheckWaitDuration": "00:02:00.0",
"healthCheckStableDuration": "00:05:00.0",
"healthCheckRetryTimeout": "00:10:00.0",
"upgradeTimeout": "01:00:00.0",
"upgradeDomainTimeout": "00:20:00.0"
},
"applicationHealthPolicy": {
"considerWarningAsError": "false",
"maxPercentUnhealthyDeployedApplications": "50",
"defaultServiceTypeHealthPolicy": {
"maxPercentUnhealthyServices": "50",
"maxPercentUnhealthyPartitionsPerService": "50",
"maxPercentUnhealthyReplicasPerPartition": "50"
}
}
}
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications/services",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameFabricObserver'), '/', variables('serviceNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationNameFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"serviceKind": "Stateless",
"serviceTypeName": "[variables('serviceTypeNameFabricObserver')]",
"instanceCount": "-1",
"partitionDescription": {
"partitionScheme": "Singleton"
},
"correlationScheme": [],
"serviceLoadMetrics": [],
"servicePlacementPolicies": []
}
}
]
}
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The Service Fabric cluster resource name from the Azure resource group. Example: servicefabriccluster123"
}
},
"applicationTypeVersionFabricObserver": {
"type": "string",
"defaultValue": "3.2.6",
"metadata": {
"description": "Provide the app version number of FabricObserver. This must be identical to the version, 3.2.6, in the referenced sfpkg specified in packageUrlFabricObserver."
}
},
"packageUrlFabricObserver": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "This has to be a public accessible URL for the sfpkg file which contains the FabricObserver app package. Example: https://github.com/microsoft/service-fabric-observer/releases/download/[xxxxxxxx]/Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained.3.2.6.sfpkg"
}
}
},
"variables": {
"applicationTypeNameFabricObserver": "FabricObserverType",
"applicationNameFabricObserver": "FabricObserver",
"serviceNameFabricObserver": "[concat(variables('applicationNameFabricObserver'), '~FabricObserverService')]",
"serviceTypeNameFabricObserver": "FabricObserverType",
"sfrpApiVersion": "2021-06-01"
},
"resources": [
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"properties": {
"provisioningState": "Default"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applicationTypes/versions",
"name": "[concat(parameters('clusterName'), '/', variables('applicationTypeNameFabricObserver'), '/', parameters('applicationTypeVersionFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"appPackageUrl": "[parameters('packageUrlFabricObserver')]"
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeNameFabricObserver'), '/versions/', parameters('applicationTypeVersionFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"typeName": "[variables('applicationTypeNameFabricObserver')]",
"typeVersion": "[parameters('applicationTypeVersionFabricObserver')]",
"parameters": {
"AppObserverEnableChildProcessMonitoring": "true",
"FabricSystemObserverEnabled": "true"
},
"upgradePolicy": {
"upgradeReplicaSetCheckTimeout": "01:00:00.0",
"forceRestart": "false",
"rollingUpgradeMonitoringPolicy": {
"healthCheckWaitDuration": "00:02:00.0",
"healthCheckStableDuration": "00:05:00.0",
"healthCheckRetryTimeout": "00:10:00.0",
"upgradeTimeout": "01:00:00.0",
"upgradeDomainTimeout": "00:20:00.0"
},
"applicationHealthPolicy": {
"considerWarningAsError": "false",
"maxPercentUnhealthyDeployedApplications": "50",
"defaultServiceTypeHealthPolicy": {
"maxPercentUnhealthyServices": "50",
"maxPercentUnhealthyPartitionsPerService": "50",
"maxPercentUnhealthyReplicasPerPartition": "50"
}
}
}
}
},
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters/applications/services",
"name": "[concat(parameters('clusterName'), '/', variables('applicationNameFabricObserver'), '/', variables('serviceNameFabricObserver'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationNameFabricObserver'))]"
],
"properties": {
"provisioningState": "Default",
"serviceKind": "Stateless",
"serviceTypeName": "[variables('serviceTypeNameFabricObserver')]",
"instanceCount": "-1",
"partitionDescription": {
"partitionScheme": "Singleton"
},
"correlationScheme": [],
"serviceLoadMetrics": [],
"servicePlacementPolicies": []
}
}
]
}

Просмотреть файл

@ -1,15 +1,15 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"value": "<YOUR-CLUSTER-RESOURCE-NAME>"
},
"applicationTypeVersionFabricObserver": {
"value": "3.2.5"
},
"packageUrlFabricObserver": {
"value": "<PUBLIC-ACCESSIBLE-URL-FOR-FABRICOBSERVER-SFPKG>"
}
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"value": "<YOUR-CLUSTER-RESOURCE-NAME>"
},
"applicationTypeVersionFabricObserver": {
"value": "3.2.6"
},
"packageUrlFabricObserver": {
"value": "<PUBLIC-ACCESSIBLE-URL-FOR-FABRICOBSERVER-SFPKG>"
}
}
}

Просмотреть файл

@ -1,99 +1,99 @@
## FabricObserver Operational Telemetry
FabricObserver operational data is transmitted to Microsoft and contains information about FabricObserver. This information helps us understand which observers matter in the real world, what type of environment they run in, and how many services are being monitored. This information will help us make sure we invest time in the right places. This data does not contain PII or any information about the services running in your cluster or the data handled by the applications. Nor do we capture the user application-specific configurations set for FO (things like target app names and metric thresholds are not transmitted. Basically, we do not care about anything that is specific to your deployment. We only care about what FO is doing with respect to its health and defined behavior.).
**This information is only used by the Service Fabric team and will be retained for no more than 90 days.**
Disabling / Enabling transmission of Operational Data:
Transmission of operational data is controlled by a setting and can be easily turned off. ```ObserverManagerEnableOperationalTelemetry``` setting in ```ApplicationManifest.xml``` controls transmission of Operational data. **Note that if you are deploying FabricObserver to a cluster running in a restricted region (China) or cloud (Gov) you should disable this feature before deploying to remain compliant. Please do not send data outside of any restricted boundary.**
Setting the value to false as below will prevent the transmission of operational data:
**\<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="false" />**
As with most of FabricObserver's application settings, you can also do this with a versionless parameter-only application upgrade:
```Powershell
Connect-ServiceFabricCluster ...
$appParams = @{ "ObserverManagerEnableOperationalFOTelemetry" = "false"; }
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/FabricObserver -ApplicationParameter $appParams -ApplicationTypeVersion 3.2.5 -UnMonitoredAuto
```
#### Questions we want to answer from data:
- Health of FO
- If FO crashes with an unhandled exception that can be caught, related error information will be sent to us (this will include the offending FO stack). This will help us improve quality.
- Enabled Observers
- Helps us focus effort on the most useful observers.
- Are there any FO plugins running?
- Is FO finding issues (generating health events)? This data is represented in the total number of Warnings/Errors an observer finds in a 24 hour window.
- This telemetry is sent once every 24 hours and internal error/warning counters are reset after each telemetry transmission.
#### Operational data details:
Here is a full example of exactly what is sent in one of these telemetry events, in this case, from an SFRP cluster:
```JSON
{
"EventName": "OperationalEvent",
"TaskName": "FabricObserver",
"EventRunInterval": "1.00:00:00",
"ClusterId": "00000000-1111-1111-0000-00f00d000d",
"ClusterType": "SFRP",
"NodeNameHash": "3e83569d4c6aad78083cd081215dafc81e5218556b6a46cb8dd2b183ed0095ad",
"FOVersion": "3.2.5",
"HasPlugins": "False",
"ParallelCapable": "True",
"SFRuntimeVersion":"9.0.1028.9590"
"UpTime": "1.00:30:18.8058379",
"Timestamp": "2022-07-08T02:45:28.9827940Z",
"OS": "Windows",
"EnabledObserverCount": 5,
"AppObserverTotalMonitoredApps": 5,
"AppObserverTotalMonitoredServiceProcesses": 11,
"AppObserverConcurrencyEnabled": 1,
"AppObserverErrorDetections": 0,
"AppObserverWarningDetections": 2,
"CertificateObserverErrorDetections": 0,
"CertificateObserverWarningDetections": 0,
"DiskObserverErrorDetections": 0,
"DiskObserverWarningDetections": 3,
"NodeObserverErrorDetections": 0,
"NodeObserverWarningDetections": 7,
"OSObserverErrorDetections": 0,
"OSObserverWarningDetections": 0
}
```
Let's take a look at the data and why we think it is useful to share with us. We'll go through each object property in the JSON above.
- **EventName** - this is the name of the telemetry event.
- **TaskName** - this specifies that the event is from FabricObserver.
- **EventRunInterval** - this is how often this telemetry is sent from a node in a cluster.
- **ClusterId** - this is used to both uniquely identify a telemetry event and to correlate data that comes from a cluster.
- **ClusterType** - this is the type of cluster: Standalone or SFRP.
- **NodeNameHash** - this is a sha256 hash of the name of the Fabric node from where the data originates. It is used to correlate data from specific nodes in a cluster (the hashed node name will be known to be part of the cluster with a specific cluster id).
- **FOVersion** - this is the internal version of FO (if you have your own version naming, we will only know what the FO code version is (not your specific FO app version name)).
- **HasPlugins** - this informs us about whether or not FO plugins are being used (we would love to know if folks are using the plugin model).
- **ParallelCapable** - this informs us about whether or not the underlying (virtual) machine's CPU configuration is parallel capable.
- **SFRuntimeVersion** - this is the version of the Service Fabric runtime.
- **UpTime** - this is the amount of time FO has been running since it last started.
- **Timestamp** - this is the time, in UTC, when FO sent the telemetry.
- **OS** - this is the operating system FO is running on (Windows or Linux).
- **AppObserverTotalMonitoredApps** - this is the total number of deployed applications AppObserver is monitoring.
- **AppObserverTotalMonitoredServiceProcesses** - this is the total number of processes AppObserver is monitoring.
- **AppObserverConcurrencyEnabled** - this informs us if AppObserver is configured to monitor processes concurrently.
- **AppObserverErrorDetections** - this is how many Error level health events AppObserver generated in a 24 hour window.
- **AppObserverWarningDetections** - this is how many Warning level health events AppObserver generated in a 24 hour window.
- **[Built-in]ObserverErrorDetections** - this is how many Error level health events [Built-in]Observer generated in a 24 hour window.
- **[Built-in]ObserverWarningDetections** - this is how many Error level health events [Built-in]Observer generated in a 24 hour window.
Note that specific plugin data, besides whether or not plugins are in use, is not captured. Only agnostic data from built-in (ship with FO) observers is collected.
If the ClusterType is not SFRP then a TenantId (Guid) is sent for use in the same way we use ClusterId.
This information will **really** help us understand how FO is doing out there and we would greatly appreciate you sharing it with us!
## FabricObserver Operational Telemetry
FabricObserver operational data is transmitted to Microsoft and contains information about FabricObserver. This information helps us understand which observers matter in the real world, what type of environment they run in, and how many services are being monitored. This information will help us make sure we invest time in the right places. This data does not contain PII or any information about the services running in your cluster or the data handled by the applications. Nor do we capture the user application-specific configurations set for FO (things like target app names and metric thresholds are not transmitted. Basically, we do not care about anything that is specific to your deployment. We only care about what FO is doing with respect to its health and defined behavior.).
**This information is only used by the Service Fabric team and will be retained for no more than 90 days.**
Disabling / Enabling transmission of Operational Data:
Transmission of operational data is controlled by a setting and can be easily turned off. ```ObserverManagerEnableOperationalTelemetry``` setting in ```ApplicationManifest.xml``` controls transmission of Operational data. **Note that if you are deploying FabricObserver to a cluster running in a restricted region (China) or cloud (Gov) you should disable this feature before deploying to remain compliant. Please do not send data outside of any restricted boundary.**
Setting the value to false as below will prevent the transmission of operational data:
**\<Parameter Name="ObserverManagerEnableOperationalTelemetry" DefaultValue="false" />**
As with most of FabricObserver's application settings, you can also do this with a versionless parameter-only application upgrade:
```Powershell
Connect-ServiceFabricCluster ...
$appParams = @{ "ObserverManagerEnableOperationalFOTelemetry" = "false"; }
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/FabricObserver -ApplicationParameter $appParams -ApplicationTypeVersion 3.2.6 -UnMonitoredAuto
```
#### Questions we want to answer from data:
- Health of FO
- If FO crashes with an unhandled exception that can be caught, related error information will be sent to us (this will include the offending FO stack). This will help us improve quality.
- Enabled Observers
- Helps us focus effort on the most useful observers.
- Are there any FO plugins running?
- Is FO finding issues (generating health events)? This data is represented in the total number of Warnings/Errors an observer finds in a 24 hour window.
- This telemetry is sent once every 24 hours and internal error/warning counters are reset after each telemetry transmission.
#### Operational data details:
Here is a full example of exactly what is sent in one of these telemetry events, in this case, from an SFRP cluster:
```JSON
{
"EventName": "OperationalEvent",
"TaskName": "FabricObserver",
"EventRunInterval": "1.00:00:00",
"ClusterId": "00000000-1111-1111-0000-00f00d000d",
"ClusterType": "SFRP",
"NodeNameHash": "3e83569d4c6aad78083cd081215dafc81e5218556b6a46cb8dd2b183ed0095ad",
"FOVersion": "3.2.6",
"HasPlugins": "False",
"ParallelCapable": "True",
"SFRuntimeVersion":"9.0.1028.9590"
"UpTime": "1.00:30:18.8058379",
"Timestamp": "2022-07-08T02:45:28.9827940Z",
"OS": "Windows",
"EnabledObserverCount": 5,
"AppObserverTotalMonitoredApps": 5,
"AppObserverTotalMonitoredServiceProcesses": 11,
"AppObserverConcurrencyEnabled": 1,
"AppObserverErrorDetections": 0,
"AppObserverWarningDetections": 2,
"CertificateObserverErrorDetections": 0,
"CertificateObserverWarningDetections": 0,
"DiskObserverErrorDetections": 0,
"DiskObserverWarningDetections": 3,
"NodeObserverErrorDetections": 0,
"NodeObserverWarningDetections": 7,
"OSObserverErrorDetections": 0,
"OSObserverWarningDetections": 0
}
```
Let's take a look at the data and why we think it is useful to share with us. We'll go through each object property in the JSON above.
- **EventName** - this is the name of the telemetry event.
- **TaskName** - this specifies that the event is from FabricObserver.
- **EventRunInterval** - this is how often this telemetry is sent from a node in a cluster.
- **ClusterId** - this is used to both uniquely identify a telemetry event and to correlate data that comes from a cluster.
- **ClusterType** - this is the type of cluster: Standalone or SFRP.
- **NodeNameHash** - this is a sha256 hash of the name of the Fabric node from where the data originates. It is used to correlate data from specific nodes in a cluster (the hashed node name will be known to be part of the cluster with a specific cluster id).
- **FOVersion** - this is the internal version of FO (if you have your own version naming, we will only know what the FO code version is (not your specific FO app version name)).
- **HasPlugins** - this informs us about whether or not FO plugins are being used (we would love to know if folks are using the plugin model).
- **ParallelCapable** - this informs us about whether or not the underlying (virtual) machine's CPU configuration is parallel capable.
- **SFRuntimeVersion** - this is the version of the Service Fabric runtime.
- **UpTime** - this is the amount of time FO has been running since it last started.
- **Timestamp** - this is the time, in UTC, when FO sent the telemetry.
- **OS** - this is the operating system FO is running on (Windows or Linux).
- **AppObserverTotalMonitoredApps** - this is the total number of deployed applications AppObserver is monitoring.
- **AppObserverTotalMonitoredServiceProcesses** - this is the total number of processes AppObserver is monitoring.
- **AppObserverConcurrencyEnabled** - this informs us if AppObserver is configured to monitor processes concurrently.
- **AppObserverErrorDetections** - this is how many Error level health events AppObserver generated in a 24 hour window.
- **AppObserverWarningDetections** - this is how many Warning level health events AppObserver generated in a 24 hour window.
- **[Built-in]ObserverErrorDetections** - this is how many Error level health events [Built-in]Observer generated in a 24 hour window.
- **[Built-in]ObserverWarningDetections** - this is how many Error level health events [Built-in]Observer generated in a 24 hour window.
Note that specific plugin data, besides whether or not plugins are in use, is not captured. Only agnostic data from built-in (ship with FO) observers is collected.
If the ClusterType is not SFRP then a TenantId (Guid) is sent for use in the same way we use ClusterId.
This information will **really** help us understand how FO is doing out there and we would greatly appreciate you sharing it with us!

Просмотреть файл

@ -1,76 +1,76 @@
## How to implement an observer plugin using FO's extensibility model
#### Note that starting in version 2.2.0, ClusterObserver supports the FO plugin model. So, you can build cluster-level monitoring plugins should you so desire.
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the target net SDK version that both FabricObserver and FabricObserver.Extensibility target.
2. Install the latest Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps into your plugin project.
3. Write an observer plugin!
E.g., create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
```C#
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
```
You must implement ObserverBase's two abstract functions:
```C#
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
```
4. Create a [PluginTypeName]Startup.cs file with this format (e.g., MyObserver is the name of your plugin class.):
```C#
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
```
5. Build your observer project, drop the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own (*same*) folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll.
6. Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file)
Update ApplicationManifest.xml with Parameters if you want to support Versionless Application Parameter-only Upgrades for your plugin.
(Look at both FabricObserver/PackageRoot/Config/Settings.xml and FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml for several examples of how to do this.)
7. Ship it! (Well, test it first =)
If you want to build your own nupkg from FO source, then:
Open a PowerShell console, navigate to the top level directory of the FO repo (in this example, C:\Users\me\source\repos\service-fabric-observer):
```PowerShell
cd C:\Users\me\source\repos\service-fabric-observer
./Build-FabricObserver
./Build-NugetPackages
```
The output from the above commands contains FabricObserver platform-specific nupkgs and a nupkg you have to use for plugin authoring named Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.5.nupkg. Nuget packages will be located in
## How to implement an observer plugin using FO's extensibility model
#### Note that starting in version 2.2.0, ClusterObserver supports the FO plugin model. So, you can build cluster-level monitoring plugins should you so desire.
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the target net SDK version that both FabricObserver and FabricObserver.Extensibility target.
2. Install the latest Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps into your plugin project.
3. Write an observer plugin!
E.g., create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
```C#
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
```
You must implement ObserverBase's two abstract functions:
```C#
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
```
4. Create a [PluginTypeName]Startup.cs file with this format (e.g., MyObserver is the name of your plugin class.):
```C#
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
```
5. Build your observer project, drop the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own (*same*) folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll.
6. Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file)
Update ApplicationManifest.xml with Parameters if you want to support Versionless Application Parameter-only Upgrades for your plugin.
(Look at both FabricObserver/PackageRoot/Config/Settings.xml and FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml for several examples of how to do this.)
7. Ship it! (Well, test it first =)
If you want to build your own nupkg from FO source, then:
Open a PowerShell console, navigate to the top level directory of the FO repo (in this example, C:\Users\me\source\repos\service-fabric-observer):
```PowerShell
cd C:\Users\me\source\repos\service-fabric-observer
./Build-FabricObserver
./Build-NugetPackages
```
The output from the above commands contains FabricObserver platform-specific nupkgs and a nupkg you have to use for plugin authoring named Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.6.nupkg. Nuget packages will be located in
C:\Users\me\source\repos\service-fabric-observer\bin\release\FabricObserver\Nugets.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="3.3.0">
<id>%PACKAGE_ID%</id>
<version>3.2.5</version>
<version>3.2.6</version>
<releaseNotes>
</releaseNotes>
<authors>Microsoft</authors>

Просмотреть файл

@ -1,35 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Platforms>x64</Platforms>
<RootNamespace>FabricObserver</RootNamespace>
<Copyright>Copyright © 2022</Copyright>
<Product>FabricObserver</Product>
<Version>3.2.5</Version>
<FileVersion>3.2.5</FileVersion>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Utilities\MemoryUsage\**" />
<EmbeddedResource Remove="Utilities\MemoryUsage\**" />
<None Remove="Utilities\MemoryUsage\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="MachineInfoModel\ConfigSettings.cs" />
<Compile Remove="MachineInfoModel\ConfigurationSetting.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.NLogTarget" Version="2.21.0" />
<PackageReference Include="Microsoft.ServiceFabric.Services" Version="6.0.1017" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
<PackageReference Include="System.Management" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Platforms>x64</Platforms>
<RootNamespace>FabricObserver</RootNamespace>
<Copyright>Copyright © 2022</Copyright>
<Product>FabricObserver</Product>
<Version>3.2.6</Version>
<FileVersion>3.2.6</FileVersion>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Utilities\MemoryUsage\**" />
<EmbeddedResource Remove="Utilities\MemoryUsage\**" />
<None Remove="Utilities\MemoryUsage\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="MachineInfoModel\ConfigSettings.cs" />
<Compile Remove="MachineInfoModel\ConfigurationSetting.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.NLogTarget" Version="2.21.0" />
<PackageReference Include="Microsoft.ServiceFabric.Services" Version="6.0.1017" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
<PackageReference Include="System.Management" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj" />
</ItemGroup>
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,291 +1,290 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace FabricObserver.Observers.Utilities
{
// Why the generic constraint on struct? Because this type only works on numeric types,
// which are all structs in .NET so it's really a partial constraint, but useful just the same.
public class FabricResourceUsageData<T> where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="FabricResourceUsageData{T}"/> class.
/// </summary>
/// <param name="property">Metric string.</param>
/// <param name="id">Instance id.</param>
/// <param name="dataCapacity">Max element capacity of instance's data container.</param>
/// <param name="useCircularBuffer">Whether to hold data in a Circular Buffer or not.</param>
public FabricResourceUsageData(
string property,
string id,
int dataCapacity,
bool useCircularBuffer = false,
bool isParallel = false)
{
if (string.IsNullOrEmpty(property))
{
throw new ArgumentException($"Must provide a non-empty {property}.");
}
if (string.IsNullOrEmpty(id))
{
throw new ArgumentException($"Must provide a non-empty {id}.");
}
// Data can be a List<T>, a CircularBufferCollection<T>, or a ConcurrentQueue<T>. \\
// CircularBufferCollection is not thread safe for writes.
if (useCircularBuffer && !isParallel)
{
Data = new CircularBufferCollection<T>(dataCapacity > 0 ? dataCapacity : 3);
}
else if (isParallel)
{
Data = new ConcurrentQueue<T>();
}
else
{
Data = new List<T>();
}
Property = property;
Id = id;
Units = string.Empty;
if (property.Contains("MB"))
{
Units = "MB";
}
if (property.Contains('%') ||
property.ToLower().Contains("cpu") ||
property.ToLower().Contains("percent"))
{
Units = "%";
}
}
/// <summary>
/// Gets or sets the name of the machine resource property this instance represents.
/// </summary>
public string Property
{
get; set;
}
/// <summary>
/// Gets or sets the unique Id of this instance.
/// </summary>
public string Id
{
get; set;
}
/// <summary>
/// Gets or sets the unit of measure for the data (%, MB/GB, etc).
/// </summary>
public string Units
{
get; set;
}
/// <summary>
/// Gets the IEnumerable type that holds the resource monitoring numeric data.
/// These can be one of generic List, CircularBufferCollection or ConcurrentQueue types.
/// </summary>
public IEnumerable<T> Data
{
get; set;
}
private bool isInWarningState;
/// <summary>
/// Gets count of total warnings for the lifetime of this instance.
/// </summary>
public int LifetimeWarningCount
{
get; private set;
}
/// <summary>
/// Gets the largest numeric value in the Data collection.
/// </summary>
public T MaxDataValue
{
get
{
if (Data?.Count() > 0)
{
return Data.Max();
}
return default;
}
}
/// <summary>
/// Gets the average value in the Data collection.
/// </summary>
public double AverageDataValue
{
get
{
double average = 0.0;
if (Data == null || !Data.Any())
{
return average;
}
switch (Data)
{
// Thread safe for reads only: List<T>, CircularBufferCollection<T> \\
case IList<long> v:
average = Math.Round(v.Average(), 2);
break;
case IList<int> x:
average = Math.Round(x.Average(), 2);
break;
case IList<float> y:
average = Math.Round(y.Average(), 2);
break;
case IList<double> z:
average = Math.Round(z.Average(), 2);
break;
// Thread safe for reads and writes: ConcurrentQueue<T> \\
case IProducerConsumerCollection<long> v:
average = Math.Round(v.Average(), 2);
break;
case IProducerConsumerCollection<int> x:
average = Math.Round(x.Average(), 2);
break;
case IProducerConsumerCollection<float> y:
average = Math.Round(y.Average(), 2);
break;
case IProducerConsumerCollection<double> z:
average = Math.Round(z.Average(), 2);
break;
}
return average;
}
}
/// <summary>
/// Gets or sets a value indicating whether there is an active Error or Warning health state on this instance.
/// Set to false when health state changes to Ok.
/// </summary>
public bool ActiveErrorOrWarning
{
get => isInWarningState;
set
{
isInWarningState = value;
if (value)
{
LifetimeWarningCount++;
}
}
}
/// <summary>
/// Gets or sets the active error or warning code (FOErorrWarningCode).
/// </summary>
public string ActiveErrorOrWarningCode
{
get; set;
}
/// <summary>
/// Determines whether or not a supplied threshold has been reached when taking the average of the values in the Data collection.
/// </summary>
/// <typeparam name="TU">Error/Warning numeric (thus struct) threshold value to determine health state.</typeparam>
/// <param name="threshold">Numeric threshold value to measure against.</param>
/// <returns>Returns true or false depending upon computed health state based on supplied threshold value.</returns>
public bool IsUnhealthy<TU>(TU threshold) where TU : struct
{
if (Data == null || !Data.Any() || Convert.ToDouble(threshold) <= 0.0)
{
return false;
}
return AverageDataValue >= Convert.ToDouble(threshold);
}
/// <summary>
/// Gets the standard deviation of the data held in the Data collection.
/// </summary>
public T StandardDeviation => Data?.Count() > 0 ? Statistics.StandardDeviation(Data) : default;
/// <summary>
/// Gets SlidingWindow Max: A sorted list of sliding window maximums. This is only availabe when Data is CircularBufferCollection.
/// </summary>
public IList<T> SlidingWindowMax => Data is CircularBufferCollection<T> && Data?.Count() >= 3 ? Statistics.SlidingWindow(Data, 3, WindowType.Max) : null;
/// <summary>
/// Gets SlidingWindow Min: A sorted list of sliding window minimums. This is only availabe when Data is CircularBufferCollection.
/// </summary>
public IList<T> SlidingWindowMin => Data is CircularBufferCollection<T> && Data ?.Count() >= 3 ? Statistics.SlidingWindow(Data, 3, WindowType.Min) : null;
/// <summary>
/// Adds numeric data to current instance's Data property. Use this method versus adding directly to Data.
/// </summary>
/// <param name="data"></param>
public void AddData(T data)
{
if (Data is List<T> d)
{
d.Add(data);
}
else if (Data is CircularBufferCollection<T> c)
{
c.Add(data);
}
else if (Data is ConcurrentQueue<T> e)
{
e.Enqueue(data);
}
}
/// <summary>
/// Clears numeric data of the current instance's Data property. Use this method versus calling Clear on Data as that
/// won't work for ConcurrentQueue.
/// </summary>
public void ClearData()
{
if (Data is List<T> d)
{
d.TrimExcess();
d.Clear();
}
else if (Data is CircularBufferCollection<T> c)
{
c.Clear();
}
else if (Data is ConcurrentQueue<T>)
{
// .NET Standard 2.0 does not have a Clear() (2.1 does).
Data = new ConcurrentQueue<T>();
}
}
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace FabricObserver.Observers.Utilities
{
// Why the generic constraint on struct? Because this type only works on numeric types,
// which are all structs in .NET so it's really a partial constraint, but useful just the same.
public class FabricResourceUsageData<T> where T : struct
{
private readonly object lockObj = new();
/// <summary>
/// Initializes a new instance of the <see cref="FabricResourceUsageData{T}"/> class.
/// </summary>
/// <param name="property">Metric string.</param>
/// <param name="id">Instance id.</param>
/// <param name="dataCapacity">Max element capacity of instance's data container.</param>
/// <param name="useCircularBuffer">Whether to hold data in a Circular Buffer or not.</param>
public FabricResourceUsageData(
string property,
string id,
int dataCapacity,
bool useCircularBuffer = false,
bool isParallel = false)
{
if (string.IsNullOrEmpty(property))
{
throw new ArgumentException($"Must provide a non-empty {property}.");
}
if (string.IsNullOrEmpty(id))
{
throw new ArgumentException($"Must provide a non-empty {id}.");
}
// Data can be a List<T>, a CircularBufferCollection<T>, or a ConcurrentQueue<T>. \\
// CircularBufferCollection is not thread safe for writes.
if (useCircularBuffer && !isParallel)
{
Data = new CircularBufferCollection<T>(dataCapacity > 0 ? dataCapacity : 3);
}
else if (isParallel)
{
Data = new ConcurrentQueue<T>();
}
else
{
Data = new List<T>();
}
Property = property;
Id = id;
Units = string.Empty;
if (property.Contains("MB"))
{
Units = "MB";
}
if (property.Contains('%') ||
property.ToLower().Contains("cpu") ||
property.ToLower().Contains("percent"))
{
Units = "%";
}
}
/// <summary>
/// Gets or sets the name of the machine resource property this instance represents.
/// </summary>
public string Property
{
get; set;
}
/// <summary>
/// Gets or sets the unique Id of this instance.
/// </summary>
public string Id
{
get; set;
}
/// <summary>
/// Gets or sets the unit of measure for the data (%, MB/GB, etc).
/// </summary>
public string Units
{
get; set;
}
/// <summary>
/// Gets the IEnumerable type that holds the resource monitoring numeric data.
/// These can be one of generic List, CircularBufferCollection or ConcurrentQueue types.
/// </summary>
public IEnumerable<T> Data
{
get; set;
}
private bool isInWarningState;
/// <summary>
/// Gets count of total warnings for the lifetime of this instance.
/// </summary>
public int LifetimeWarningCount
{
get; private set;
}
/// <summary>
/// Gets the largest numeric value in the Data collection.
/// </summary>
public T MaxDataValue
{
get
{
if (Data?.Count() > 0)
{
return Data.Max();
}
return default;
}
}
/// <summary>
/// Gets the average value in the Data collection.
/// </summary>
public double AverageDataValue
{
get
{
double average = 0.0;
if (Data == null || !Data.Any())
{
return average;
}
switch (Data)
{
// Thread safe for reads only: List<T>, CircularBufferCollection<T> \\
case IList<long> v:
average = Math.Round(v.Average(), 2);
break;
case IList<int> x:
average = Math.Round(x.Average(), 2);
break;
case IList<float> y:
average = Math.Round(y.Average(), 2);
break;
case IList<double> z:
average = Math.Round(z.Average(), 2);
break;
// Thread safe for reads and writes: ConcurrentQueue<T> \\
case IProducerConsumerCollection<long> v:
average = Math.Round(v.Average(), 2);
break;
case IProducerConsumerCollection<int> x:
average = Math.Round(x.Average(), 2);
break;
case IProducerConsumerCollection<float> y:
average = Math.Round(y.Average(), 2);
break;
case IProducerConsumerCollection<double> z:
average = Math.Round(z.Average(), 2);
break;
}
return average;
}
}
/// <summary>
/// Gets or sets a value indicating whether there is an active Error or Warning health state on this instance.
/// Set to false when health state changes to Ok.
/// </summary>
public bool ActiveErrorOrWarning
{
get => isInWarningState;
set
{
isInWarningState = value;
if (value)
{
LifetimeWarningCount++;
}
}
}
/// <summary>
/// Gets or sets the active error or warning code (FOErorrWarningCode).
/// </summary>
public string ActiveErrorOrWarningCode
{
get; set;
}
/// <summary>
/// Determines whether or not a supplied threshold has been reached when taking the average of the values in the Data collection.
/// </summary>
/// <typeparam name="TU">Error/Warning numeric (thus struct) threshold value to determine health state.</typeparam>
/// <param name="threshold">Numeric threshold value to measure against.</param>
/// <returns>Returns true or false depending upon computed health state based on supplied threshold value.</returns>
public bool IsUnhealthy<TU>(TU threshold) where TU : struct
{
if (Data == null || !Data.Any() || Convert.ToDouble(threshold) <= 0.0)
{
return false;
}
return AverageDataValue >= Convert.ToDouble(threshold);
}
/// <summary>
/// Gets the standard deviation of the data held in the Data collection.
/// </summary>
public T StandardDeviation => Data?.Count() > 0 ? Statistics.StandardDeviation(Data) : default;
/// <summary>
/// Gets SlidingWindow Max: A sorted list of sliding window maximums. This is only availabe when Data is CircularBufferCollection.
/// </summary>
public IList<T> SlidingWindowMax => Data is CircularBufferCollection<T> && Data?.Count() >= 3 ? Statistics.SlidingWindow(Data, 3, WindowType.Max) : null;
/// <summary>
/// Gets SlidingWindow Min: A sorted list of sliding window minimums. This is only availabe when Data is CircularBufferCollection.
/// </summary>
public IList<T> SlidingWindowMin => Data is CircularBufferCollection<T> && Data ?.Count() >= 3 ? Statistics.SlidingWindow(Data, 3, WindowType.Min) : null;
/// <summary>
/// Adds numeric data to current instance's Data property. Use this method versus adding directly to Data.
/// </summary>
/// <param name="data"></param>
public void AddData(T data)
{
if (Data is List<T> d)
{
d.Add(data);
}
else if (Data is CircularBufferCollection<T> c)
{
c.Add(data);
}
else if (Data is ConcurrentQueue<T> e)
{
e.Enqueue(data);
}
}
/// <summary>
/// Clears numeric data of the current instance's Data property.
/// </summary>
public void ClearData()
{
if (Data is List<T> list)
{
list.Clear();
}
else if (Data is CircularBufferCollection<T> cBuffer)
{
cBuffer.Clear();
}
else if (Data is ConcurrentQueue<T> conQ)
{
conQ.Clear();
}
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -378,7 +378,7 @@ namespace FabricObserver.Observers.Utilities
if (Marshal.GetLastWin32Error() != 5)
{
ProcessInfoLogger.LogWarning($"GetProcessMemoryMbPerfCounter: The specified process (name: {procName}, pid: {procId}) isn't the droid we're looking for. " +
$"Error Code: {Marshal.GetLastWin32Error()}");
$"Error Code: {Marshal.GetLastWin32Error()}");
}
return 0F;
@ -398,7 +398,7 @@ namespace FabricObserver.Observers.Utilities
if (!hasWarnedProcessNameLength)
{
ProcessInfoLogger.LogWarning(
$"Process name {procName} exceeds max length (64) for Performance Counter InstanceName (.NET Core) property. " +
$"GetProcessMemoryMbPerfCounter: Process name {procName} exceeds max length (64) for Performance Counter InstanceName (.NET Core) property. " +
$"Supplying Full Working Set (Private + Shared, Win32 API) value instead. " +
$"Will not log this again until FO restarts.");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,420 +1,434 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Fabric;
using System.Fabric.Health;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FabricObserver.Observers.Interfaces;
using FabricObserver.TelemetryLib;
using Newtonsoft.Json;
namespace FabricObserver.Observers.Utilities.Telemetry
{
// LogAnalyticsTelemetry class is partially (SendTelemetryAsync/GetSignature) based on public sample: https://dejanstojanovic.net/aspnet/2018/february/send-data-to-azure-log-analytics-from-c-code/
public class LogAnalyticsTelemetry : ITelemetryProvider
{
private const string ApiVersion = "2016-04-01";
private readonly Logger logger;
private string WorkspaceId
{
get;
}
private string LogType
{
get;
}
private string TargetUri => $"https://{WorkspaceId}.ods.opinsights.azure.com/api/logs?api-version={ApiVersion}";
public string Key
{
get; set;
}
/// <summary>
/// Sends telemetry data to Azure LogAnalytics via REST.
/// </summary>
/// <param name="payload">Json string containing telemetry data.</param>
/// <param name="cancellationToken">CancellationToken instance.</param>
/// <returns>A completed task or task containing exception info.</returns>
private async Task SendTelemetryAsync(string payload, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(payload) || cancellationToken.IsCancellationRequested)
{
return;
}
try
{
string date = DateTime.UtcNow.ToString("r");
string signature = GetSignature("POST", payload.Length, "application/json", date, "/api/logs");
byte[] content = Encoding.UTF8.GetBytes(payload);
using HttpClient httpClient = new();
using HttpRequestMessage request = new(HttpMethod.Post, TargetUri);
request.Headers.Authorization = AuthenticationHeaderValue.Parse(signature);
request.Content = new ByteArrayContent(content);
request.Content.Headers.Add("Content-Type", "application/json");
request.Content.Headers.Add("Log-Type", LogType);
request.Content.Headers.Add("x-ms-date", date);
using var response = await httpClient.SendAsync(request, cancellationToken);
if (response != null && (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Accepted))
{
return;
}
if (response != null)
{
logger.LogWarning(
$"Unexpected response from server in LogAnalyticsTelemetry.SendTelemetryAsync:{Environment.NewLine}{response.StatusCode}: {response.ReasonPhrase}");
}
}
catch (Exception e) when (e is HttpRequestException || e is InvalidOperationException)
{
logger.LogInfo($"Exception sending telemetry to LogAnalytics service:{Environment.NewLine}{e.Message}");
}
catch (Exception e)
{
// Do not take down FO with a telemetry fault. Log it. Warning level will always log.
// This means there is either a bug in this code or something else that needs your attention.
#if DEBUG
logger.LogWarning($"Exception sending telemetry to LogAnalytics service:{Environment.NewLine}{e}");
#else
logger.LogWarning($"Exception sending telemetry to LogAnalytics service: {e.Message}");
#endif
}
}
private string GetSignature(
string method,
int contentLength,
string contentType,
string date,
string resource)
{
string message = $"{method}\n{contentLength}\n{contentType}\nx-ms-date:{date}\n{resource}";
byte[] bytes = Encoding.UTF8.GetBytes(message);
using HMACSHA256 encryptor = new(Convert.FromBase64String(Key));
return $"SharedKey {WorkspaceId}:{Convert.ToBase64String(encryptor.ComputeHash(bytes))}";
}
public LogAnalyticsTelemetry(
string workspaceId,
string sharedKey,
string logType)
{
WorkspaceId = workspaceId;
Key = sharedKey;
LogType = logType;
logger = new Logger("TelemetryLogger");
}
public async Task ReportHealthAsync(
string propertyName,
HealthState state,
string unhealthyEvaluations,
string source,
CancellationToken cancellationToken,
string serviceName = null,
string instanceName = null)
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterInformation.ClusterInfoTuple.ClusterId,
source,
property = propertyName,
healthState = state.ToString(),
healthEvaluation = unhealthyEvaluations,
serviceName = serviceName ?? string.Empty,
instanceName = instanceName ?? string.Empty,
osPlatform = OperatingSystem.IsWindows() ? "Windows" : "Linux"
});
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
public async Task ReportHealthAsync(TelemetryDataBase telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (telemetryData is ServiceTelemetryData serviceTelemData)
{
if (JsonHelper.TrySerializeObject(serviceTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is NodeTelemetryData nodeTelemData)
{
if (JsonHelper.TrySerializeObject(nodeTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is DiskTelemetryData diskTelemData)
{
if (JsonHelper.TrySerializeObject(diskTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is ClusterTelemetryData clusterTelemData)
{
if (JsonHelper.TrySerializeObject(clusterTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else
{
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
}
public async Task ReportMetricAsync(TelemetryDataBase telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (telemetryData is ServiceTelemetryData serviceTelemData)
{
if (JsonHelper.TrySerializeObject(serviceTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is NodeTelemetryData nodeTelemData)
{
if (JsonHelper.TrySerializeObject(nodeTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is DiskTelemetryData diskTelemData)
{
if (JsonHelper.TrySerializeObject(diskTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is ClusterTelemetryData clusterTelemData)
{
if (JsonHelper.TrySerializeObject(clusterTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else
{
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
}
public async Task ReportMetricAsync(List<ChildProcessTelemetryData> telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
public async Task ReportMetricAsync(MachineTelemetryData machineTelemetryData, CancellationToken cancellationToken)
{
if (machineTelemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (JsonHelper.TrySerializeObject(machineTelemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
public async Task<bool> ReportMetricAsync<T>(
string name,
T value,
string source,
CancellationToken cancellationToken)
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
id = $"FO_{Guid.NewGuid()}",
datetime = DateTime.UtcNow,
ClusterInformation.ClusterInfoTuple.ClusterId,
source,
property = name,
value
});
await SendTelemetryAsync(jsonPayload, cancellationToken);
return await Task.FromResult(true);
}
public async Task ReportClusterUpgradeStatusAsync(ServiceFabricUpgradeEventData eventData, CancellationToken token)
{
if (eventData?.FabricUpgradeProgress == null || token.IsCancellationRequested)
{
return;
}
try
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterId = ServiceFabricUpgradeEventData.ClusterId ?? ClusterInformation.ClusterInfoTuple.ClusterId,
Timestamp = DateTime.UtcNow,
eventData.OS,
CurrentUpgradeDomain = eventData.FabricUpgradeProgress.CurrentUpgradeDomainProgress?.UpgradeDomainName,
eventData.FabricUpgradeProgress?.NextUpgradeDomain,
UpgradeTargetCodeVersion = eventData.FabricUpgradeProgress.UpgradeDescription?.TargetCodeVersion,
UpgradeTargetConfigVersion = eventData.FabricUpgradeProgress.UpgradeDescription?.TargetConfigVersion,
UpgradeState = Enum.GetName(typeof(FabricUpgradeState), eventData.FabricUpgradeProgress.UpgradeState),
UpgradeDuration = eventData.FabricUpgradeProgress.CurrentUpgradeDomainDuration,
FailureReason = eventData.FabricUpgradeProgress.FailureReason.HasValue ? Enum.GetName(typeof(UpgradeFailureReason), eventData.FabricUpgradeProgress.FailureReason.Value) : null,
});
await SendTelemetryAsync(jsonPayload, token).ConfigureAwait(true);
}
catch (Exception e)
{
// Telemetry is non-critical and should not take down FH.
logger.LogWarning($"Failure in ReportClusterUpgradeStatus:{Environment.NewLine}{e}");
}
}
public async Task ReportApplicationUpgradeStatusAsync(ServiceFabricUpgradeEventData eventData, CancellationToken token)
{
if (eventData?.ApplicationUpgradeProgress == null || token.IsCancellationRequested)
{
return;
}
try
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterId = ServiceFabricUpgradeEventData.ClusterId ?? ClusterInformation.ClusterInfoTuple.ClusterId,
Timestamp = DateTime.UtcNow,
eventData.OS,
ApplicationName = eventData.ApplicationUpgradeProgress.ApplicationName?.OriginalString,
CurrentUpgradeDomain = eventData.ApplicationUpgradeProgress.CurrentUpgradeDomainProgress?.UpgradeDomainName,
eventData.ApplicationUpgradeProgress?.NextUpgradeDomain,
UpgradeTargetAppTypeVersion = eventData.ApplicationUpgradeProgress.UpgradeDescription?.TargetApplicationTypeVersion,
UpgradeState = Enum.GetName(typeof(FabricUpgradeState), eventData.ApplicationUpgradeProgress.UpgradeState),
UpgradeDuration = eventData.ApplicationUpgradeProgress.CurrentUpgradeDomainDuration,
FailureReason = eventData.ApplicationUpgradeProgress.FailureReason.HasValue ? Enum.GetName(typeof(UpgradeFailureReason), eventData.ApplicationUpgradeProgress.FailureReason.Value) : null,
});
await SendTelemetryAsync(jsonPayload, token).ConfigureAwait(true);
}
catch (Exception e)
{
// Telemetry is non-critical and should not take down FH.
logger.LogWarning($"Failure in ReportClusterUpgradeStatus:{Environment.NewLine}{e}");
}
}
public async Task ReportNodeSnapshotAsync(NodeSnapshotTelemetryData nodeSnapshotTelem, CancellationToken cancellationToken)
{
if (JsonHelper.TrySerializeObject(nodeSnapshotTelem, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
// Implement functions below as you need.
public Task ReportAvailabilityAsync(
Uri serviceUri,
string instance,
string testName,
DateTimeOffset captured,
TimeSpan duration,
string location,
bool success,
CancellationToken cancellationToken,
string message = null)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string name,
long value,
IDictionary<string, string> properties,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string service,
Guid partition,
string name,
long value,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string role,
long id,
string name,
long value,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string roleName,
string instance,
string name,
long value,
int count,
long min,
long max,
long sum,
double deviation,
IDictionary<string, string> properties,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Fabric;
using System.Fabric.Health;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FabricObserver.Observers.Interfaces;
using FabricObserver.TelemetryLib;
using Newtonsoft.Json;
namespace FabricObserver.Observers.Utilities.Telemetry
{
// LogAnalyticsTelemetry class is partially (SendTelemetryAsync/GetSignature) based on public sample: https://dejanstojanovic.net/aspnet/2018/february/send-data-to-azure-log-analytics-from-c-code/
public class LogAnalyticsTelemetry : ITelemetryProvider
{
private const string ApiVersion = "2016-04-01";
private readonly Logger logger;
private string WorkspaceId
{
get;
}
private string LogType
{
get;
}
private string TargetUri => $"https://{WorkspaceId}.ods.opinsights.azure.com/api/logs?api-version={ApiVersion}";
public string Key
{
get; set;
}
/// <summary>
/// Sends telemetry data to Azure LogAnalytics via REST.
/// </summary>
/// <param name="payload">Json string containing telemetry data.</param>
/// <param name="cancellationToken">CancellationToken instance.</param>
/// <returns>A completed task or task containing exception info.</returns>
private async Task SendTelemetryAsync(string payload, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(payload) || cancellationToken.IsCancellationRequested)
{
return;
}
try
{
string date = DateTime.UtcNow.ToString("r");
string signature = GetSignature("POST", payload.Length, "application/json", date, "/api/logs");
byte[] content = Encoding.UTF8.GetBytes(payload);
using HttpClient httpClient = new();
using HttpRequestMessage request = new(HttpMethod.Post, TargetUri);
request.Headers.Authorization = AuthenticationHeaderValue.Parse(signature);
request.Content = new ByteArrayContent(content);
request.Content.Headers.Add("Content-Type", "application/json");
request.Content.Headers.Add("Log-Type", LogType);
request.Content.Headers.Add("x-ms-date", date);
using var response = await httpClient.SendAsync(request, cancellationToken);
if (response != null && (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Accepted))
{
return;
}
if (response != null)
{
logger.LogWarning(
$"Unexpected response from server in LogAnalyticsTelemetry.SendTelemetryAsync:{Environment.NewLine}{response.StatusCode}: {response.ReasonPhrase}");
}
}
catch (Exception e) when (e is HttpRequestException || e is InvalidOperationException)
{
logger.LogInfo($"Exception sending telemetry to LogAnalytics service:{Environment.NewLine}{e.Message}");
}
catch (Exception e)
{
// Do not take down FO with a telemetry fault. Log it. Warning level will always log.
// This means there is either a bug in this code or something else that needs your attention.
#if DEBUG
logger.LogWarning($"Exception sending telemetry to LogAnalytics service:{Environment.NewLine}{e}");
#else
logger.LogWarning($"Exception sending telemetry to LogAnalytics service: {e.Message}");
#endif
if (e is OutOfMemoryException) // Since this can be handled, don't handle it.
{
throw;
}
}
}
private string GetSignature(
string method,
int contentLength,
string contentType,
string date,
string resource)
{
string message = $"{method}\n{contentLength}\n{contentType}\nx-ms-date:{date}\n{resource}";
byte[] bytes = Encoding.UTF8.GetBytes(message);
using HMACSHA256 encryptor = new(Convert.FromBase64String(Key));
return $"SharedKey {WorkspaceId}:{Convert.ToBase64String(encryptor.ComputeHash(bytes))}";
}
public LogAnalyticsTelemetry(
string workspaceId,
string sharedKey,
string logType)
{
WorkspaceId = workspaceId;
Key = sharedKey;
LogType = logType;
logger = new Logger("TelemetryLogger");
}
public async Task ReportHealthAsync(
string propertyName,
HealthState state,
string unhealthyEvaluations,
string source,
CancellationToken cancellationToken,
string serviceName = null,
string instanceName = null)
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterInformation.ClusterInfoTuple.ClusterId,
source,
property = propertyName,
healthState = state.ToString(),
healthEvaluation = unhealthyEvaluations,
serviceName = serviceName ?? string.Empty,
instanceName = instanceName ?? string.Empty,
osPlatform = OperatingSystem.IsWindows() ? "Windows" : "Linux"
});
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
public async Task ReportHealthAsync(TelemetryDataBase telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (telemetryData is ServiceTelemetryData serviceTelemData)
{
if (JsonHelper.TrySerializeObject(serviceTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is NodeTelemetryData nodeTelemData)
{
if (JsonHelper.TrySerializeObject(nodeTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is DiskTelemetryData diskTelemData)
{
if (JsonHelper.TrySerializeObject(diskTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is ClusterTelemetryData clusterTelemData)
{
if (JsonHelper.TrySerializeObject(clusterTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else
{
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
}
public async Task ReportMetricAsync(TelemetryDataBase telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (telemetryData is ServiceTelemetryData serviceTelemData)
{
if (JsonHelper.TrySerializeObject(serviceTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is NodeTelemetryData nodeTelemData)
{
if (JsonHelper.TrySerializeObject(nodeTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is DiskTelemetryData diskTelemData)
{
if (JsonHelper.TrySerializeObject(diskTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else if (telemetryData is ClusterTelemetryData clusterTelemData)
{
if (JsonHelper.TrySerializeObject(clusterTelemData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
else
{
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
}
public async Task ReportMetricAsync(List<ChildProcessTelemetryData> telemetryData, CancellationToken cancellationToken)
{
if (telemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (JsonHelper.TrySerializeObject(telemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
public async Task ReportMetricAsync(MachineTelemetryData machineTelemetryData, CancellationToken cancellationToken)
{
if (machineTelemetryData == null || cancellationToken.IsCancellationRequested)
{
return;
}
if (JsonHelper.TrySerializeObject(machineTelemetryData, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
public async Task<bool> ReportMetricAsync<T>(
string name,
T value,
string source,
CancellationToken cancellationToken)
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
id = $"FO_{Guid.NewGuid()}",
datetime = DateTime.UtcNow,
ClusterInformation.ClusterInfoTuple.ClusterId,
source,
property = name,
value
});
await SendTelemetryAsync(jsonPayload, cancellationToken);
return await Task.FromResult(true);
}
public async Task ReportClusterUpgradeStatusAsync(ServiceFabricUpgradeEventData eventData, CancellationToken token)
{
if (eventData?.FabricUpgradeProgress == null || token.IsCancellationRequested)
{
return;
}
try
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterId = ServiceFabricUpgradeEventData.ClusterId ?? ClusterInformation.ClusterInfoTuple.ClusterId,
Timestamp = DateTime.UtcNow,
eventData.OS,
CurrentUpgradeDomain = eventData.FabricUpgradeProgress.CurrentUpgradeDomainProgress?.UpgradeDomainName,
eventData.FabricUpgradeProgress?.NextUpgradeDomain,
UpgradeTargetCodeVersion = eventData.FabricUpgradeProgress.UpgradeDescription?.TargetCodeVersion,
UpgradeTargetConfigVersion = eventData.FabricUpgradeProgress.UpgradeDescription?.TargetConfigVersion,
UpgradeState = Enum.GetName(typeof(FabricUpgradeState), eventData.FabricUpgradeProgress.UpgradeState),
UpgradeDuration = eventData.FabricUpgradeProgress.CurrentUpgradeDomainDuration,
FailureReason = eventData.FabricUpgradeProgress.FailureReason.HasValue ? Enum.GetName(typeof(UpgradeFailureReason), eventData.FabricUpgradeProgress.FailureReason.Value) : null,
});
await SendTelemetryAsync(jsonPayload, token).ConfigureAwait(true);
}
catch (Exception e)
{
// Telemetry is non-critical and should not take down FH.
logger.LogWarning($"Failure in ReportClusterUpgradeStatus:{Environment.NewLine}{e.Message}");
if (e is OutOfMemoryException) // Since this can be handled, don't handle it.
{
throw;
}
}
}
public async Task ReportApplicationUpgradeStatusAsync(ServiceFabricUpgradeEventData eventData, CancellationToken token)
{
if (eventData?.ApplicationUpgradeProgress == null || token.IsCancellationRequested)
{
return;
}
try
{
string jsonPayload = JsonConvert.SerializeObject(
new
{
ClusterId = ServiceFabricUpgradeEventData.ClusterId ?? ClusterInformation.ClusterInfoTuple.ClusterId,
Timestamp = DateTime.UtcNow,
eventData.OS,
ApplicationName = eventData.ApplicationUpgradeProgress.ApplicationName?.OriginalString,
CurrentUpgradeDomain = eventData.ApplicationUpgradeProgress.CurrentUpgradeDomainProgress?.UpgradeDomainName,
eventData.ApplicationUpgradeProgress?.NextUpgradeDomain,
UpgradeTargetAppTypeVersion = eventData.ApplicationUpgradeProgress.UpgradeDescription?.TargetApplicationTypeVersion,
UpgradeState = Enum.GetName(typeof(FabricUpgradeState), eventData.ApplicationUpgradeProgress.UpgradeState),
UpgradeDuration = eventData.ApplicationUpgradeProgress.CurrentUpgradeDomainDuration,
FailureReason = eventData.ApplicationUpgradeProgress.FailureReason.HasValue ? Enum.GetName(typeof(UpgradeFailureReason), eventData.ApplicationUpgradeProgress.FailureReason.Value) : null,
});
await SendTelemetryAsync(jsonPayload, token).ConfigureAwait(true);
}
catch (Exception e)
{
// Telemetry is non-critical and should not take down FH.
logger.LogWarning($"Failure in ReportClusterUpgradeStatus:{Environment.NewLine}{e.Message}");
if (e is OutOfMemoryException) // Since this can be handled, don't handle it.
{
throw;
}
}
}
public async Task ReportNodeSnapshotAsync(NodeSnapshotTelemetryData nodeSnapshotTelem, CancellationToken cancellationToken)
{
if (JsonHelper.TrySerializeObject(nodeSnapshotTelem, out string jsonPayload))
{
await SendTelemetryAsync(jsonPayload, cancellationToken);
}
}
// Implement functions below as you need.
public Task ReportAvailabilityAsync(
Uri serviceUri,
string instance,
string testName,
DateTimeOffset captured,
TimeSpan duration,
string location,
bool success,
CancellationToken cancellationToken,
string message = null)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string name,
long value,
IDictionary<string, string> properties,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string service,
Guid partition,
string name,
long value,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string role,
long id,
string name,
long value,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task ReportMetricAsync(
string roleName,
string instance,
string name,
long value,
int count,
long min,
long max,
long sum,
double deviation,
IDictionary<string, string> properties,
CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -2,13 +2,9 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="3.3.0">
<id>%PACKAGE_ID%</id>
<version>3.2.5</version>
<version>3.2.6</version>
<releaseNotes>
- New telemetry data types: NodeTelemetryData, ServiceTelemetryData, DiskTelemetryData. These types hold only the relevant information for the target entity. For backwards compatibility, TelemetryData type still exists.
- FabricObserver is now only shipped as a .NET 6 application. There is no longer support for .NET Core 3.1.
- FabricObserver targets the Service Fabric 9.x runtime and SF SDK versions 6.0.1017 and later. *This version will not run on earlier versions of the SF runtime.* There are no longer multiple releases of FO that target different SF runtime/.NET versions.
- NodeObserver can be configured to emit Node snapshots (only useful if you employ ApplicationInsights/LogAnalytics/ETW).
- Bug fixes and several code improvements.
</releaseNotes>
<authors>Microsoft</authors>
<license type="expression">MIT</license>
@ -17,7 +13,7 @@
<icon>icon.png</icon>
<readme>fonuget.md</readme>
<language>en-US</language>
<description>This package contains the FabricObserver(FO) Application - built for .NET 6.0 and SF Runtime 9.x. FO a highly configurable and extensible resource usage watchdog service that is designed to be run in Azure Service Fabric Windows and Linux clusters. This package contains the entire application and can be used to build .NET Standard 2.0 observer plugins. NOTE: If you want to target .NET 6 for your plugins, then you must use Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.5 nuget package to build them.</description>
<description>This package contains the FabricObserver(FO) Application - built for .NET 6.0 and SF Runtime 9.x. FO a highly configurable and extensible resource usage watchdog service that is designed to be run in Azure Service Fabric Windows and Linux clusters. This package contains the entire application and can be used to build .NET Standard 2.0 observer plugins. NOTE: If you want to target .NET 6 for your plugins, then you must use Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.6 nuget package to build them.</description>
<contentFiles>
<files include="**" buildAction="None" copyToOutput="true" />
</contentFiles>

Просмотреть файл

@ -1,153 +1,153 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E27A9B40-7F6A-4C9B-91EC-A8AC6C2DC009}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
Build-ClusterObserver.ps1 = Build-ClusterObserver.ps1
Build-CONugetPackages.ps1 = Build-CONugetPackages.ps1
Build-COSFPkgs.ps1 = Build-COSFPkgs.ps1
Build-FabricObserver.ps1 = Build-FabricObserver.ps1
Build-NugetPackages.ps1 = Build-NugetPackages.ps1
Build-SFPkgs.ps1 = Build-SFPkgs.ps1
ClusterObserver.nuspec.template = ClusterObserver.nuspec.template
conuget.md = conuget.md
Documentation\Deployment\Deploy-FabricObserver.ps1 = Documentation\Deployment\Deploy-FabricObserver.ps1
Documentation\Deployment\Deployment.md = Documentation\Deployment\Deployment.md
Documentation\Design.md = Documentation\Design.md
Documentation\ErrorCodes.md = Documentation\ErrorCodes.md
Documentation\ETW.md = Documentation\ETW.md
FabricObserver.Extensibility.nuspec.template = FabricObserver.Extensibility.nuspec.template
FabricObserver.nuspec.template = FabricObserver.nuspec.template
FOAzurePipeline.yaml = FOAzurePipeline.yaml
foextlib.md = foextlib.md
fonuget.md = fonuget.md
icon.png = icon.png
NuGet.config = NuGet.config
Documentation\Observers.md = Documentation\Observers.md
Documentation\OperationalTelemetry.md = Documentation\OperationalTelemetry.md
Documentation\Plugins.md = Documentation\Plugins.md
README.md = README.md
SECURITY.md = SECURITY.md
Documentation\Deployment\service-fabric-cluster-observer.json = Documentation\Deployment\service-fabric-cluster-observer.json
Documentation\Deployment\service-fabric-cluster-observer.v2.2.2.parameters.json = Documentation\Deployment\service-fabric-cluster-observer.v2.2.2.parameters.json
Documentation\Deployment\service-fabric-observer.json = Documentation\Deployment\service-fabric-observer.json
Documentation\Deployment\service-fabric-observer.v3.2.5.parameters.json = Documentation\Deployment\service-fabric-observer.v3.2.5.parameters.json
Documentation\Using.md = Documentation\Using.md
EndProjectSection
EndProject
Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "ClusterObserverApp", "ClusterObserverApp\ClusterObserverApp.sfproj", "{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClusterObserver", "ClusterObserver\ClusterObserver.csproj", "{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserver", "FabricObserver\FabricObserver.csproj", "{51AC2A69-B952-4766-8A1E-2C7752BC011A}"
EndProject
Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "FabricObserverApp", "FabricObserverApp\FabricObserverApp.sfproj", "{59F966A9-5566-4ADB-A84F-42C3372D8744}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelemetryLib", "TelemetryLib\TelemetryLib.csproj", "{7BC6991F-C840-413E-B1CD-4025947CF5FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserverTests", "FabricObserverTests\FabricObserverTests.csproj", "{48C88BEB-9960-4183-861B-DF25C193E4C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleObserverPlugin", "SampleObserverPlugin\SampleObserverPlugin.csproj", "{4549560C-4604-42C3-B055-BDBD80B5B291}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserver.Extensibility", "FabricObserver.Extensibility\FabricObserver.Extensibility.csproj", "{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlDiffPatchSF", "XmlDiffPatchSF\XmlDiffPatchSF.csproj", "{2AC4F67C-015B-4655-AF8A-0A4285AA7067}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.ActiveCfg = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.Build.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.Deploy.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.ActiveCfg = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.Build.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.Deploy.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.ActiveCfg = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.Build.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.Deploy.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.ActiveCfg = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.Build.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.Deploy.0 = Release|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|Any CPU.ActiveCfg = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|Any CPU.Build.0 = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|x64.ActiveCfg = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|x64.Build.0 = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|Any CPU.Build.0 = Release|Any CPU
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|x64.ActiveCfg = Release|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|x64.Build.0 = Release|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|Any CPU.ActiveCfg = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|Any CPU.Build.0 = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|x64.ActiveCfg = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|x64.Build.0 = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|Any CPU.Build.0 = Release|Any CPU
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|x64.ActiveCfg = Release|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|x64.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.ActiveCfg = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.Build.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.Deploy.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.ActiveCfg = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.Build.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.Deploy.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.ActiveCfg = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.Deploy.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.ActiveCfg = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.Deploy.0 = Release|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|Any CPU.ActiveCfg = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|Any CPU.Build.0 = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|x64.ActiveCfg = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|x64.Build.0 = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|Any CPU.Build.0 = Release|Any CPU
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|x64.ActiveCfg = Release|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|x64.Build.0 = Release|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|x64.ActiveCfg = Debug|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|x64.Build.0 = Debug|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|Any CPU.Build.0 = Release|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|x64.ActiveCfg = Release|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|x64.Build.0 = Release|x64
{4549560C-4604-42C3-B055-BDBD80B5B291}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4549560C-4604-42C3-B055-BDBD80B5B291}.Debug|x64.ActiveCfg = Debug|x64
{4549560C-4604-42C3-B055-BDBD80B5B291}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4549560C-4604-42C3-B055-BDBD80B5B291}.Release|x64.ActiveCfg = Release|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|x64.ActiveCfg = Debug|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|x64.Build.0 = Debug|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|Any CPU.Build.0 = Release|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|x64.ActiveCfg = Release|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|x64.Build.0 = Release|x64
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|x64.ActiveCfg = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|Any CPU.Build.0 = Release|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AC046A6F-D408-473A-BF49-6CF00F8E2F44}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E27A9B40-7F6A-4C9B-91EC-A8AC6C2DC009}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
Build-ClusterObserver.ps1 = Build-ClusterObserver.ps1
Build-CONugetPackages.ps1 = Build-CONugetPackages.ps1
Build-COSFPkgs.ps1 = Build-COSFPkgs.ps1
Build-FabricObserver.ps1 = Build-FabricObserver.ps1
Build-NugetPackages.ps1 = Build-NugetPackages.ps1
Build-SFPkgs.ps1 = Build-SFPkgs.ps1
ClusterObserver.nuspec.template = ClusterObserver.nuspec.template
conuget.md = conuget.md
Documentation\Deployment\Deploy-FabricObserver.ps1 = Documentation\Deployment\Deploy-FabricObserver.ps1
Documentation\Deployment\Deployment.md = Documentation\Deployment\Deployment.md
Documentation\Design.md = Documentation\Design.md
Documentation\ErrorCodes.md = Documentation\ErrorCodes.md
Documentation\ETW.md = Documentation\ETW.md
FabricObserver.Extensibility.nuspec.template = FabricObserver.Extensibility.nuspec.template
FabricObserver.nuspec.template = FabricObserver.nuspec.template
FOAzurePipeline.yaml = FOAzurePipeline.yaml
foextlib.md = foextlib.md
fonuget.md = fonuget.md
icon.png = icon.png
NuGet.config = NuGet.config
Documentation\Observers.md = Documentation\Observers.md
Documentation\OperationalTelemetry.md = Documentation\OperationalTelemetry.md
Documentation\Plugins.md = Documentation\Plugins.md
README.md = README.md
SECURITY.md = SECURITY.md
Documentation\Deployment\service-fabric-cluster-observer.json = Documentation\Deployment\service-fabric-cluster-observer.json
Documentation\Deployment\service-fabric-observer.json = Documentation\Deployment\service-fabric-observer.json
Documentation\Deployment\service-fabric-cluster-observer.v2.2.3.parameters.json = Documentation\Deployment\service-fabric-cluster-observer.v2.2.3.parameters.json
Documentation\Using.md = Documentation\Using.md
Documentation\Deployment\service-fabric-observer.v3.2.6.parameters.json = Documentation\Deployment\service-fabric-observer.v3.2.6.parameters.json
EndProjectSection
EndProject
Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "ClusterObserverApp", "ClusterObserverApp\ClusterObserverApp.sfproj", "{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClusterObserver", "ClusterObserver\ClusterObserver.csproj", "{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserver", "FabricObserver\FabricObserver.csproj", "{51AC2A69-B952-4766-8A1E-2C7752BC011A}"
EndProject
Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "FabricObserverApp", "FabricObserverApp\FabricObserverApp.sfproj", "{59F966A9-5566-4ADB-A84F-42C3372D8744}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelemetryLib", "TelemetryLib\TelemetryLib.csproj", "{7BC6991F-C840-413E-B1CD-4025947CF5FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserverTests", "FabricObserverTests\FabricObserverTests.csproj", "{48C88BEB-9960-4183-861B-DF25C193E4C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleObserverPlugin", "SampleObserverPlugin\SampleObserverPlugin.csproj", "{4549560C-4604-42C3-B055-BDBD80B5B291}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabricObserver.Extensibility", "FabricObserver.Extensibility\FabricObserver.Extensibility.csproj", "{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlDiffPatchSF", "XmlDiffPatchSF\XmlDiffPatchSF.csproj", "{2AC4F67C-015B-4655-AF8A-0A4285AA7067}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.ActiveCfg = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.Build.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|Any CPU.Deploy.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.ActiveCfg = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.Build.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Debug|x64.Deploy.0 = Debug|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.ActiveCfg = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.Build.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|Any CPU.Deploy.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.ActiveCfg = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.Build.0 = Release|x64
{BD5D216F-5F89-4CC4-92FD-D6FDEC5A19AD}.Release|x64.Deploy.0 = Release|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|Any CPU.ActiveCfg = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|Any CPU.Build.0 = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|x64.ActiveCfg = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Debug|x64.Build.0 = Debug|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|Any CPU.Build.0 = Release|Any CPU
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|x64.ActiveCfg = Release|x64
{5E990052-7B55-4AF1-BCD9-48DE6EA0E547}.Release|x64.Build.0 = Release|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|Any CPU.ActiveCfg = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|Any CPU.Build.0 = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|x64.ActiveCfg = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Debug|x64.Build.0 = Debug|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|Any CPU.Build.0 = Release|Any CPU
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|x64.ActiveCfg = Release|x64
{51AC2A69-B952-4766-8A1E-2C7752BC011A}.Release|x64.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.ActiveCfg = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.Build.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|Any CPU.Deploy.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.ActiveCfg = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.Build.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Debug|x64.Deploy.0 = Debug|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.ActiveCfg = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|Any CPU.Deploy.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.ActiveCfg = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.Build.0 = Release|x64
{59F966A9-5566-4ADB-A84F-42C3372D8744}.Release|x64.Deploy.0 = Release|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|Any CPU.ActiveCfg = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|Any CPU.Build.0 = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|x64.ActiveCfg = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Debug|x64.Build.0 = Debug|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|Any CPU.Build.0 = Release|Any CPU
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|x64.ActiveCfg = Release|x64
{7BC6991F-C840-413E-B1CD-4025947CF5FA}.Release|x64.Build.0 = Release|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|x64.ActiveCfg = Debug|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Debug|x64.Build.0 = Debug|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|Any CPU.Build.0 = Release|Any CPU
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|x64.ActiveCfg = Release|x64
{48C88BEB-9960-4183-861B-DF25C193E4C9}.Release|x64.Build.0 = Release|x64
{4549560C-4604-42C3-B055-BDBD80B5B291}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4549560C-4604-42C3-B055-BDBD80B5B291}.Debug|x64.ActiveCfg = Debug|x64
{4549560C-4604-42C3-B055-BDBD80B5B291}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4549560C-4604-42C3-B055-BDBD80B5B291}.Release|x64.ActiveCfg = Release|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|x64.ActiveCfg = Debug|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Debug|x64.Build.0 = Debug|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|Any CPU.Build.0 = Release|Any CPU
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|x64.ActiveCfg = Release|x64
{9C9D92E0-A246-4F74-92F4-CD8A9B76B1B5}.Release|x64.Build.0 = Release|x64
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Debug|x64.ActiveCfg = Debug|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|Any CPU.Build.0 = Release|Any CPU
{2AC4F67C-015B-4655-AF8A-0A4285AA7067}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AC046A6F-D408-473A-BF49-6CF00F8E2F44}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,137 +1,137 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Fabric;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using FabricObserver.Observers;
using McMaster.NETCore.Plugins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Services.Runtime;
namespace FabricObserver
{
/// <summary>
/// An instance of this class is created for each service instance by the Service Fabric runtime.
/// </summary>
internal sealed class FabricObserverService : StatelessService
{
/// <summary>
/// Initializes a new instance of the type.
/// </summary>
/// <param name="context">StatelessServiceContext instance.</param>
public FabricObserverService(StatelessServiceContext context) : base(context)
{
}
/// <summary>
/// This is the main entry point for your service instance.
/// </summary>
/// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
/// <returns>a Task.</returns>
protected override async Task RunAsync(CancellationToken cancellationToken)
{
var services = new ServiceCollection();
ConfigureServices(services);
await using ServiceProvider serviceProvider = services.BuildServiceProvider();
using var observerManager = new ObserverManager(serviceProvider, cancellationToken);
await observerManager.StartObserversAsync();
}
/// <summary>
/// This function will add observer instances, both static (observers that are already implemented in FabricObserver) and dynamic (custom observer plugin dlls).
/// </summary>
/// <param name="services">ServiceCollection collection instance.</param>
private void ConfigureServices(IServiceCollection services)
{
_ = services.AddScoped(typeof(ObserverBase), s => new AppObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new AzureStorageUploadObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new CertificateObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new ContainerObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new DiskObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new FabricSystemObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new NetworkObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new NodeObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new OSObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new SFConfigurationObserver(Context));
_ = services.AddSingleton(typeof(StatelessServiceContext), Context);
LoadObserversFromPlugins(services);
}
/// <summary>
/// This function will load observer plugin dlls from PackageRoot/Data/Plugins folder and add them to the ServiceCollection instance.
/// </summary>
/// <param name="services"></param>
private void LoadObserversFromPlugins(IServiceCollection services)
{
string pluginsDir = Path.Combine(Context.CodePackageActivationContext.GetDataPackageObject("Data").Path, "Plugins");
if (!Directory.Exists(pluginsDir))
{
return;
}
string[] pluginDlls = Directory.GetFiles(pluginsDir, "*.dll", SearchOption.AllDirectories);
if (pluginDlls.Length == 0)
{
return;
}
PluginLoader[] pluginLoaders = new PluginLoader[pluginDlls.Length];
Type[] sharedTypes = { typeof(FabricObserverStartupAttribute), typeof(IFabricObserverStartup), typeof(IServiceCollection) };
for (int i = 0; i < pluginDlls.Length; ++i)
{
string dll = pluginDlls[i];
PluginLoader loader = PluginLoader.CreateFromAssemblyFile(dll, sharedTypes, a => a.IsUnloadable = false);
pluginLoaders[i] = loader;
}
for (int i = 0; i < pluginLoaders.Length; ++i)
{
var pluginLoader = pluginLoaders[i];
Assembly pluginAssembly;
try
{
// If your plugin has native library dependencies (that's fine), then we will land in the catch (BadImageFormatException).
// This is by design. The Managed FO plugin assembly will successfully load, of course.
pluginAssembly = pluginLoader.LoadDefaultAssembly();
FabricObserverStartupAttribute[] startupAttributes = pluginAssembly.GetCustomAttributes<FabricObserverStartupAttribute>().ToArray();
for (int j = 0; j < startupAttributes.Length; ++j)
{
object startupObject = Activator.CreateInstance(startupAttributes[j].StartupType);
if (startupObject is IFabricObserverStartup fabricObserverStartup)
{
// The null parameter (re FabricClient) is used here *only to preserve the existing (historical, in use..) interface specification for IFabricObserverStartup*.
// There is actually no longer a need to pass in a FabricClient instance as this is now a singleton instance managed by
// FabricObserver.Extensibility.FabricClientUtilities that protects against premature disposal (by plugins, for example).
fabricObserverStartup.ConfigureServices(services, null, Context);
}
else
{
// This will bring down FO, which it should: This means your plugin is not supported. Fix your bug.
throw new InvalidOperationException($"{startupAttributes[j].StartupType.FullName} must implement IFabricObserverStartup.");
}
}
}
catch (Exception e) when (e is ArgumentException || e is BadImageFormatException || e is IOException)
{
continue;
}
}
}
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Fabric;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using FabricObserver.Observers;
using McMaster.NETCore.Plugins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Services.Runtime;
namespace FabricObserver
{
/// <summary>
/// An instance of this class is created for each service instance by the Service Fabric runtime.
/// </summary>
internal sealed class FabricObserverService : StatelessService
{
/// <summary>
/// Initializes a new instance of the type.
/// </summary>
/// <param name="context">StatelessServiceContext instance.</param>
public FabricObserverService(StatelessServiceContext context) : base(context)
{
}
/// <summary>
/// This is the main entry point for your service instance.
/// </summary>
/// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
/// <returns>a Task.</returns>
protected override async Task RunAsync(CancellationToken cancellationToken)
{
var services = new ServiceCollection();
ConfigureServices(services);
await using ServiceProvider serviceProvider = services.BuildServiceProvider();
using var observerManager = new ObserverManager(serviceProvider, cancellationToken);
await observerManager.StartObserversAsync();
}
/// <summary>
/// This function will add observer instances, both static (observers that are already implemented in FabricObserver) and dynamic (custom observer plugin dlls).
/// </summary>
/// <param name="services">ServiceCollection collection instance.</param>
private void ConfigureServices(IServiceCollection services)
{
_ = services.AddScoped(typeof(ObserverBase), s => new AppObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new AzureStorageUploadObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new CertificateObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new ContainerObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new DiskObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new FabricSystemObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new NetworkObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new NodeObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new OSObserver(Context));
_ = services.AddScoped(typeof(ObserverBase), s => new SFConfigurationObserver(Context));
_ = services.AddSingleton(typeof(StatelessServiceContext), Context);
LoadObserversFromPlugins(services);
}
/// <summary>
/// This function will load observer plugin dlls from PackageRoot/Data/Plugins folder and add them to the ServiceCollection instance.
/// </summary>
/// <param name="services"></param>
private void LoadObserversFromPlugins(IServiceCollection services)
{
string pluginsDir = Path.Combine(Context.CodePackageActivationContext.GetDataPackageObject("Data").Path, "Plugins");
if (!Directory.Exists(pluginsDir))
{
return;
}
string[] pluginDlls = Directory.GetFiles(pluginsDir, "*.dll", SearchOption.AllDirectories);
if (pluginDlls.Length == 0)
{
return;
}
PluginLoader[] pluginLoaders = new PluginLoader[pluginDlls.Length];
Type[] sharedTypes = { typeof(FabricObserverStartupAttribute), typeof(IFabricObserverStartup), typeof(IServiceCollection) };
for (int i = 0; i < pluginDlls.Length; ++i)
{
string dll = pluginDlls[i];
PluginLoader loader = PluginLoader.CreateFromAssemblyFile(dll, sharedTypes, a => a.IsUnloadable = false);
pluginLoaders[i] = loader;
}
for (int i = 0; i < pluginLoaders.Length; ++i)
{
var pluginLoader = pluginLoaders[i];
Assembly pluginAssembly;
try
{
// If your plugin has native library dependencies (that's fine), then we will land in the catch (BadImageFormatException).
// This is by design. The Managed FO plugin assembly will successfully load, of course.
pluginAssembly = pluginLoader.LoadDefaultAssembly();
FabricObserverStartupAttribute[] startupAttributes = pluginAssembly.GetCustomAttributes<FabricObserverStartupAttribute>().ToArray();
for (int j = 0; j < startupAttributes.Length; ++j)
{
object startupObject = Activator.CreateInstance(startupAttributes[j].StartupType);
if (startupObject is IFabricObserverStartup fabricObserverStartup)
{
// The null parameter (re FabricClient) is used here *only to preserve the existing (historical, in use..) interface specification for IFabricObserverStartup*.
// There is actually no longer a need to pass in a FabricClient instance as this is now a singleton instance managed by
// FabricObserver.Extensibility.FabricClientUtilities that protects against premature disposal (by plugins, for example).
fabricObserverStartup.ConfigureServices(services, null, Context);
}
else
{
// This will bring down FO, which it should: This means your plugin is not supported. Fix your bug.
throw new InvalidOperationException($"{startupAttributes[j].StartupType.FullName} must implement IFabricObserverStartup.");
}
}
}
catch (Exception e) when (e is ArgumentException || e is BadImageFormatException || e is IOException)
{
continue;
}
}
}
}
}

Просмотреть файл

@ -1,81 +1,81 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{51AC2A69-B952-4766-8A1E-2C7752BC011A}</ProjectGuid>
<RootNamespace>FabricObserver</RootNamespace>
<AssemblyName>FabricObserver</AssemblyName>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<TargetLatestRuntimePatch>True</TargetLatestRuntimePatch>
<Copyright>Copyright © 2022</Copyright>
<Product>FabricObserver</Product>
<Version>3.2.5</Version>
<FileVersion>3.2.5</FileVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<IsServiceFabricServiceProject>true</IsServiceFabricServiceProject>
<StartupObject>FabricObserver.Program</StartupObject>
<NoWarn>CA1822;$(NoWarn)</NoWarn>
<ResolveComReferenceSilent>true</ResolveComReferenceSilent>
<Platforms>x64</Platforms>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Connected Services\**" />
<EmbeddedResource Remove="Connected Services\**" />
<None Remove="Connected Services\**" />
</ItemGroup>
<ItemGroup>
<None Remove="ApplicationInsights.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.14.1" />
<PackageReference Include="Octokit" Version="5.0.0" />
<PackageReference Include="System.Diagnostics.EventLog" Version="7.0.0" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<Reference Include="..\Interop\Interop.WUApiLib.dll" />
</ItemGroup>
<ItemGroup>
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="PackageRoot\Config\Settings.xml">
<SubType>Designer</SubType>
</None>
<None Include="PackageRoot\Config\AppObserver.config.json" />
<None Include="PackageRoot\Config\ContainerObserver.config.json" />
<None Include="PackageRoot\Config\NetworkObserver.config.json" />
<None Include="PackageRoot\ServiceManifest.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FabricObserver.Extensibility\FabricObserver.Extensibility.csproj">
<Private>true</Private>
</ProjectReference>
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj">
<Private>true</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Update="elevated_docker_stats">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="elevated_netstat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="elevated_proc_fd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="install_lvid_perfcounter.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="setcaps.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{51AC2A69-B952-4766-8A1E-2C7752BC011A}</ProjectGuid>
<RootNamespace>FabricObserver</RootNamespace>
<AssemblyName>FabricObserver</AssemblyName>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<TargetLatestRuntimePatch>True</TargetLatestRuntimePatch>
<Copyright>Copyright © 2022</Copyright>
<Product>FabricObserver</Product>
<Version>3.2.6</Version>
<FileVersion>3.2.6</FileVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<IsServiceFabricServiceProject>true</IsServiceFabricServiceProject>
<StartupObject>FabricObserver.Program</StartupObject>
<NoWarn>CA1822;$(NoWarn)</NoWarn>
<ResolveComReferenceSilent>true</ResolveComReferenceSilent>
<Platforms>x64</Platforms>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Connected Services\**" />
<EmbeddedResource Remove="Connected Services\**" />
<None Remove="Connected Services\**" />
</ItemGroup>
<ItemGroup>
<None Remove="ApplicationInsights.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.14.1" />
<PackageReference Include="Octokit" Version="5.0.0" />
<PackageReference Include="System.Diagnostics.EventLog" Version="7.0.0" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<Reference Include="..\Interop\Interop.WUApiLib.dll" />
</ItemGroup>
<ItemGroup>
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="PackageRoot\Config\Settings.xml">
<SubType>Designer</SubType>
</None>
<None Include="PackageRoot\Config\AppObserver.config.json" />
<None Include="PackageRoot\Config\ContainerObserver.config.json" />
<None Include="PackageRoot\Config\NetworkObserver.config.json" />
<None Include="PackageRoot\ServiceManifest.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FabricObserver.Extensibility\FabricObserver.Extensibility.csproj">
<Private>true</Private>
</ProjectReference>
<ProjectReference Include="..\TelemetryLib\TelemetryLib.csproj">
<Private>true</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Update="elevated_docker_stats">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="elevated_netstat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="elevated_proc_fd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="install_lvid_perfcounter.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="setcaps.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -96,8 +96,7 @@ namespace FabricObserver.Observers
{
if (handleToProcSnapshot == null)
{
handleToProcSnapshot =
NativeMethods.CreateToolhelp32Snapshot((uint)NativeMethods.CreateToolhelp32SnapshotFlags.TH32CS_SNAPPROCESS, 0);
handleToProcSnapshot = NativeMethods.CreateProcessSnapshot();
if (handleToProcSnapshot.IsInvalid)
{
@ -2560,16 +2559,19 @@ namespace FabricObserver.Observers
double cpu = 0;
cpu = cpuUsage.GetCurrentCpuUsagePercentage(procId, IsWindows ? procName : null);
// procId is no longer mapped to process. see CpuUsageProcess/CpuUsageWin32 impls.
if (cpu < 0)
{
continue;
}
if (procId == parentPid)
{
// process is no longer mapped to process name.
if (cpu > 0)
{
AllAppCpuData[id].AddData(cpu);
}
AllAppCpuData[id].AddData(cpu);
}
else
{
// Add new child proc entry if not already present in dictionary.
_ = AllAppCpuData.TryAdd(
$"{id}:{procName}{procId}",
new FabricResourceUsageData<double>(
@ -2583,7 +2585,7 @@ namespace FabricObserver.Observers
}
}
Thread.Sleep(50);
Thread.Sleep(150);
}
timer.Stop();

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,72 +1,72 @@
Your Observer plugins must live in this folder.
-- How to implement an observer plugin with our extensibility model --
Note that the observer API lives in its own library, FabricObserver.Extensibility.dll. FO also uses this library for its internal observer impls.
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the .NET SDK version that both FabricObserver and FabricObserver.Extensibility target.
2. Install the same version of the Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps as the version of FabricObserver you are deploying.
E.g., 3.2.5 if you are going to deploy FO 3.2.5.
NOTE: You can also consume the entire FabricObserver 3.2.5 nupkg to build your plugin. Please see the SampleObserverPlugin project's csproj file for more information.
3. Write an observer plugin!
E.g., create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
You must implement ObserverBase's two abstract functions:
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
4. Create a [PluginTypeName]Startup.cs file with this format (e.g., MyObserver is the name of your plugin class.):
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
5. Build your observer project, drop the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own (*same*) folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll.
6. Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file).
Update ApplicationManifest.xml with App Parameters if you want to support Versionless Parameter-only Application Upgrades for your plugin. If not, then just use Settings.xml to host your setting values.
Look at both FabricObserver/PackageRoot/Config/Settings.xml and FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml for several examples of how to do this.
7. Ship it! (Well, test it first =)
If you want to build your own nupkg from FO source, then:
Open a PowerShell console, navigate to the top level directory of the FO repo (in this example, C:\Users\me\source\repos\service-fabric-observer):
cd C:\Users\me\source\repos\service-fabric-observer
./Build-FabricObserver
./Build-NugetPackages
The output from the above commands contains FabricObserver platform-specific nupkgs and a package you have to use for plugin authoring named Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.5.nupkg. Nupkg files from above command would be located in
Your Observer plugins must live in this folder.
-- How to implement an observer plugin with our extensibility model --
Note that the observer API lives in its own library, FabricObserver.Extensibility.dll. FO also uses this library for its internal observer impls.
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the .NET SDK version that both FabricObserver and FabricObserver.Extensibility target.
2. Install the same version of the Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps as the version of FabricObserver you are deploying.
E.g., 3.2.6 if you are going to deploy FO 3.2.6.
NOTE: You can also consume the entire FabricObserver 3.2.6 nupkg to build your plugin. Please see the SampleObserverPlugin project's csproj file for more information.
3. Write an observer plugin!
E.g., create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
You must implement ObserverBase's two abstract functions:
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
4. Create a [PluginTypeName]Startup.cs file with this format (e.g., MyObserver is the name of your plugin class.):
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
5. Build your observer project, drop the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own (*same*) folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll.
6. Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file).
Update ApplicationManifest.xml with App Parameters if you want to support Versionless Parameter-only Application Upgrades for your plugin. If not, then just use Settings.xml to host your setting values.
Look at both FabricObserver/PackageRoot/Config/Settings.xml and FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml for several examples of how to do this.
7. Ship it! (Well, test it first =)
If you want to build your own nupkg from FO source, then:
Open a PowerShell console, navigate to the top level directory of the FO repo (in this example, C:\Users\me\source\repos\service-fabric-observer):
cd C:\Users\me\source\repos\service-fabric-observer
./Build-FabricObserver
./Build-NugetPackages
The output from the above commands contains FabricObserver platform-specific nupkgs and a package you have to use for plugin authoring named Microsoft.ServiceFabricApps.FabricObserver.Extensibility.3.2.6.nupkg. Nupkg files from above command would be located in
C:\Users\me\source\repos\service-fabric-observer\bin\release\FabricObserver\Nugets.

Просмотреть файл

@ -1,34 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="FabricObserverPkg"
Version="3.2.5"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="FabricObserverType" />
</ServiceTypes>
<CodePackage Name="Code" Version="3.2.5">
<SetupEntryPoint>
<ExeHost>
<Program>install_lvid_perfcounter.bat</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</SetupEntryPoint>
<EntryPoint>
<ExeHost>
<Program>FabricObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="3.2.5" />
<!-- Data package is the contents of the Data directory under PackageRoot that contains an
independently-updateable and versioned custom data for your service.
Observer plugin dlls must live in this folder, in a child folder named Plugins. -->
<DataPackage Name="Data" Version="3.2.5" />
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="FabricObserverPkg"
Version="3.2.6"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="FabricObserverType" />
</ServiceTypes>
<CodePackage Name="Code" Version="3.2.6">
<SetupEntryPoint>
<ExeHost>
<Program>install_lvid_perfcounter.bat</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</SetupEntryPoint>
<EntryPoint>
<ExeHost>
<Program>FabricObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="3.2.6" />
<!-- Data package is the contents of the Data directory under PackageRoot that contains an
independently-updateable and versioned custom data for your service.
Observer plugin dlls must live in this folder, in a child folder named Plugins. -->
<DataPackage Name="Data" Version="3.2.6" />
</ServiceManifest>

Просмотреть файл

@ -1,36 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="FabricObserverPkg"
Version="3.2.5"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="FabricObserverType" />
</ServiceTypes>
<!-- Code package is your service executable. -->
<CodePackage Name="Code" Version="3.2.5">
<SetupEntryPoint>
<ExeHost>
<Program>setcaps.sh</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</SetupEntryPoint>
<EntryPoint>
<ExeHost>
<Program>FabricObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="3.2.5" />
<!-- Data package is the contents of the Data directory under PackageRoot that contains an
independently-updateable and versioned custom data for your service.
Observer plugin dlls must live in this folder, in a child folder named Plugins. -->
<DataPackage Name="Data" Version="3.2.5" />
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="FabricObserverPkg"
Version="3.2.6"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<!-- This is the name of your ServiceType.
This name must match the string used in RegisterServiceType call in Program.cs. -->
<StatelessServiceType ServiceTypeName="FabricObserverType" />
</ServiceTypes>
<!-- Code package is your service executable. -->
<CodePackage Name="Code" Version="3.2.6">
<SetupEntryPoint>
<ExeHost>
<Program>setcaps.sh</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</SetupEntryPoint>
<EntryPoint>
<ExeHost>
<Program>FabricObserver</Program>
</ExeHost>
</EntryPoint>
</CodePackage>
<!-- Config package is the contents of the Config directory under PackageRoot that contains an
independently-updateable and versioned set of custom configuration settings for your service. -->
<ConfigPackage Name="Config" Version="3.2.6" />
<!-- Data package is the contents of the Data directory under PackageRoot that contains an
independently-updateable and versioned custom data for your service.
Observer plugin dlls must live in this folder, in a child folder named Plugins. -->
<DataPackage Name="Data" Version="3.2.6" />
</ServiceManifest>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- You can try the XML diff/merge tool XmlDiffPatchSF (located in this repo) to make upgrading your base configurations to the latest version much easier. -->
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="FabricObserverType" ApplicationTypeVersion="3.2.5" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="FabricObserverType" ApplicationTypeVersion="3.2.6" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<!-- ObserverManager Configuration -->
<Parameter Name="ObserverManagerObserverLoopSleepTimeSeconds" DefaultValue="30" />
@ -31,8 +31,8 @@
<!-- Note: You must run FO as System or Admin user on Windows in order to run ContainerObserver on Windows. -->
<Parameter Name="ContainerObserverEnabled" DefaultValue="false" />
<Parameter Name="DiskObserverEnabled" DefaultValue="true" />
<Parameter Name="FabricSystemObserverEnabled" DefaultValue="false" />
<Parameter Name="NetworkObserverEnabled" DefaultValue="false" />
<Parameter Name="FabricSystemObserverEnabled" DefaultValue="true" />
<Parameter Name="NetworkObserverEnabled" DefaultValue="true" />
<Parameter Name="NodeObserverEnabled" DefaultValue="true" />
<Parameter Name="OSObserverEnabled" DefaultValue="true" />
<!-- Deprecated: SFConfigurationObserver is only useful if you deploy the now-obsolete (and unsupported) FabricObserverWebApi application. -->
@ -83,14 +83,14 @@
Set this to 1 second if AppObserver is monitoring several services AND FO is running on a VM/Machine with insufficient number of logical processors (< 4). -->
<Parameter Name="AppObserverMonitorDuration" DefaultValue="00:00:01" />
<Parameter Name="FabricSystemObserverMonitorDuration" DefaultValue="00:00:01" />
<Parameter Name="NodeObserverMonitorDuration" DefaultValue="00:00:05" />
<Parameter Name="NodeObserverMonitorDuration" DefaultValue="00:00:10" />
<!-- Run Intervals (TimeSpan format, e.g., 0.00:00:00): How often an enabled observer should run. -->
<Parameter Name="AppObserverRunInterval" DefaultValue="" />
<Parameter Name="AzureStorageUploadObserverRunInterval" DefaultValue="00:05:00" />
<Parameter Name="CertificateObserverRunInterval" DefaultValue="1.00:00:00" />
<Parameter Name="ContainerObserverRunInterval" DefaultValue="" />
<Parameter Name="DiskObserverRunInterval" DefaultValue="00:15:00" />
<Parameter Name="FabricSystemObserverRunInterval" DefaultValue="00:15:00" />
<Parameter Name="DiskObserverRunInterval" DefaultValue="" />
<Parameter Name="FabricSystemObserverRunInterval" DefaultValue="" />
<Parameter Name="NetworkObserverRunInterval" DefaultValue="" />
<Parameter Name="NodeObserverRunInterval" DefaultValue="" />
<Parameter Name="OSObserverRunInterval" DefaultValue="00:15:00" />
@ -232,7 +232,7 @@
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="FabricObserverPkg" ServiceManifestVersion="3.2.5" />
<ServiceManifestRef ServiceManifestName="FabricObserverPkg" ServiceManifestVersion="3.2.6" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,4 +1,4 @@
## FabricObserver 3.2.5
## FabricObserver 3.2.6
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fservice-fabric-observer%2Fmain%2FDocumentation%2FDeployment%2Fservice-fabric-observer.json)
@ -84,7 +84,7 @@ see [FOAzurePipeline.yaml](/FOAzurePipeline.yaml) for msazure devops build tasks
.net6 installed (if you deploy VM images from Azure gallery, then they will not have .net6 installed), then you must deploy the SelfContained package.</strong>
### Deploy FabricObserver
**Note: You must deploy this version (3.2.5) to clusters that are running SF 9.0 and above. This version also requires .NET 6.**
**Note: You must deploy this version (3.2.6) to clusters that are running SF 9.0 and above. This version also requires .NET 6.**
You can deploy FabricObserver (and ClusterObserver) using Visual Studio (if you build the sources yourself), PowerShell or ARM. Please note that this version of FabricObserver no longer supports the DefaultServices node in ApplicationManifest.xml.
This means that should you deploy using PowerShell, you must create an instance of the service as the last command in your script. This was done to support ARM deployment, specifically.
The StartupServices.xml file you see in the FabricHealerApp project now contains the service information once held in ApplicationManifest's DefaultServices node. Note that this information is primarily useful for deploying from Visual Studio.
@ -132,7 +132,7 @@ Register-ServiceFabricApplicationType -ApplicationPathInImageStore FO32960
#Create FO application (if not already deployed at lesser version):
New-ServiceFabricApplication -ApplicationName fabric:/FabricObserver -ApplicationTypeName FabricObserverType -ApplicationTypeVersion 3.2.5
New-ServiceFabricApplication -ApplicationName fabric:/FabricObserver -ApplicationTypeName FabricObserverType -ApplicationTypeVersion 3.2.6
#Create the Service instances (-1 means all nodes, which is what is required for FO):
@ -140,7 +140,7 @@ New-ServiceFabricService -Stateless -PartitionSchemeSingleton -ApplicationName f
#OR if updating existing version:
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/FabricObserver -ApplicationTypeVersion 3.2.5 -Monitored -FailureAction rollback
Start-ServiceFabricApplicationUpgrade -ApplicationName fabric:/FabricObserver -ApplicationTypeVersion 3.2.6 -Monitored -FailureAction rollback
```
## Observer Model

Просмотреть файл

@ -1,36 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- You could target netstandard2.0 instead, if you need to. But you probably do not need to.
In the .NET 6+ age, moving away from netstandard2.0 is generally a good idea, in many cases; this being one of them. -->
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>linux-x64;win-x64</RuntimeIdentifiers>
<RootNamespace>FabricObserver.Observers</RootNamespace>
<AssemblyName>SampleNewObserver</AssemblyName>
<Platforms>x64</Platforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<!-- Copy files post-build. -->
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<!-- Polly.dll from packages (this file is only required by this sample plugin, not FabricObserver itself..). -->
<Exec Command="copy &quot;$(SolutionDir)packages\polly\7.2.3\lib\netstandard2.0\Polly.dll&quot; &quot;$(OutDir)&quot;&#xD;&#xA;" />
<!-- If you build with the full FO nuget pkg, uncomment the line below and comment out the Extensibility library package reference. -->
<!-- <Exec Command="copy &quot;$(OutDir)*.dll&quot; &quot;$(OutDir)FabricObserverPkg\Data\Plugins&quot;&#xD;&#xA;copy &quot;$(OutDir)*.pdb&quot; &quot;$(OutDir)FabricObserverPkg\Data\Plugins&quot;" /> -->
</Target>
<ItemGroup>
<!-- To build with the full 3.2.5 FO nupkg. The output dir will contain a FabricObserverPkg folder with Code/Config/Data.
So, you can deploy FO directly from there. -->
<!-- <PackageReference Include="Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained" Version="3.2.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> -->
<!-- OR -->
<!-- Build with *just* the FabricObserver.Extensibility library. There will be no FabricObserverPkg folder in outdir.. -->
<PackageReference Include="Microsoft.ServiceFabricApps.FabricObserver.Extensibility" Version="3.2.5" />
<!-- This is an external nupkg that this plugin sample requires. This is unrelated to the above FO-related reference choices. -->
<PackageReference Include="Polly" Version="7.2.3" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- You could target netstandard2.0 instead, if you need to. But you probably do not need to.
In the .NET 6+ age, moving away from netstandard2.0 is generally a good idea, in many cases; this being one of them. -->
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>linux-x64;win-x64</RuntimeIdentifiers>
<RootNamespace>FabricObserver.Observers</RootNamespace>
<AssemblyName>SampleNewObserver</AssemblyName>
<Platforms>x64</Platforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<!-- Copy files post-build. -->
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<!-- Polly.dll from packages (this file is only required by this sample plugin, not FabricObserver itself..). -->
<Exec Command="copy &quot;$(SolutionDir)packages\polly\7.2.3\lib\netstandard2.0\Polly.dll&quot; &quot;$(OutDir)&quot;&#xD;&#xA;" />
<!-- If you build with the full FO nuget pkg, uncomment the line below and comment out the Extensibility library package reference. -->
<!-- <Exec Command="copy &quot;$(OutDir)*.dll&quot; &quot;$(OutDir)FabricObserverPkg\Data\Plugins&quot;&#xD;&#xA;copy &quot;$(OutDir)*.pdb&quot; &quot;$(OutDir)FabricObserverPkg\Data\Plugins&quot;" /> -->
</Target>
<ItemGroup>
<!-- To build with the full 3.2.6 FO nupkg. The output dir will contain a FabricObserverPkg folder with Code/Config/Data.
So, you can deploy FO directly from there. -->
<!-- <PackageReference Include="Microsoft.ServiceFabricApps.FabricObserver.Windows.SelfContained" Version="3.2.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> -->
<!-- OR -->
<!-- Build with *just* the FabricObserver.Extensibility library. There will be no FabricObserverPkg folder in outdir.. -->
<PackageReference Include="Microsoft.ServiceFabricApps.FabricObserver.Extensibility" Version="3.2.6" />
<!-- This is an external nupkg that this plugin sample requires. This is unrelated to the above FO-related reference choices. -->
<PackageReference Include="Polly" Version="7.2.3" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,179 +1,179 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Xml;
using Microsoft.XmlDiffPatch;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Linq;
namespace DiffPatchXmlSF
{
internal class Program
{
private static void Main(string[] args)
{
// Help..
if (args.Length == 1 && args[0] == "?")
{
Console.WriteLine(
"\nThis utility takes 2 required unnamed parameters, [currentXmlFileFullPath] and [latestXmlFileFullPath], and two optional parameters, [outputFileFullPath], [mergeExistingNodes].\n" +
"The first two parameters should be different versions of the *same* configuration file, where the current version is the one you want to patch/merge into the latest version (v1.0 -> v2.0, etc).\n" +
"The patch preserves the current version's settings values for elements/attributes that also exist in the latest version.\n" +
"If the optional [outputFileFullPath] arg is not provided, then the patched file name will be [latestXmlFileFullPath] appended with \"_patched\" " +
"preceding the file extension.\n\n" +
"**Note, if you have observer plugins, then you must supply true for [mergeExistingNodes] as the last argument to pull over your plugin settings as part of the merge.**.\n\n" +
"Example:\n\n" +
"DiffPatchXml \"C:\\repos\\FO\\3.1.26\\configs\\ApplicationManifest.xml\" \"C:\\repos\\FO\\3.2.5\\configs\\ApplicationManifest.xml\"\n");
return;
}
if (args.Length == 0 || args.Length < 2)
{
Console.WriteLine("Please pass the right parameters (2), e.g.,\n\n\t DiffPatchXml [currentXmlFileFullPath] [latestXmlFileFullPath]");
return;
}
if (!File.Exists(args[0]) || !File.Exists(args[1]))
{
Console.WriteLine("Supplied xml configuration files must exist.");
return;
}
string currentFileVersionPath = args[0];
string latestFileVersionPath = args[1];
try
{
var currentXml = XDocument.Load(currentFileVersionPath);
var latestXml = XDocument.Load(latestFileVersionPath);
currentXml = null;
latestXml = null;
}
catch (XmlException)
{
Console.WriteLine("Only XML is supported.");
return;
}
string diffgramFilePath = Path.GetTempFileName();
string patchedFilePath = Path.Combine(Path.GetDirectoryName(latestFileVersionPath), Path.GetFileNameWithoutExtension(latestFileVersionPath) + "_patched.xml");
bool mergeExistingNodes = false;
if (args.Length == 3 && !bool.TryParse(args[2], out mergeExistingNodes))
{
patchedFilePath = args[2];
}
else if (args.Length == 4)
{
_ = bool.TryParse(args[3], out mergeExistingNodes);
patchedFilePath = args[2];
}
DiffPatchXmlFiles(currentFileVersionPath, latestFileVersionPath, diffgramFilePath, patchedFilePath, mergeExistingNodes);
}
private static void DiffPatchXmlFiles(string currentVersionFilePath, string latestVersionFilePath, string diffGramFilePath, string patchedFilePath, bool mergeExistingNodes = false)
{
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Entitize,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
CheckCharacters = true,
Indent = true,
DoNotEscapeUriAttributes = true,
NewLineOnAttributes = false
};
XmlWriter output = null;
try
{
output = XmlWriter.Create(diffGramFilePath, settings);
GenerateXmlDiffGram(currentVersionFilePath, latestVersionFilePath, ref output);
}
finally
{
output.Dispose();
}
/* Remove changed values from old configs to support carry over to new version, which generally (not always) may have new elements.
This enables a master config's values to be preserved across app config upgrades of a Service Fabric app's base configuration (AppManifest and Settings).
Based on https://stackoverflow.com/questions/14341490/programmatic-xml-diff-merge-in-c-sharp */
XNamespace xd = "http://schemas.microsoft.com/xmltools/2002/xmldiff";
var xdoc = XDocument.Load(diffGramFilePath);
// xd:change -> match -> @DefaultValue is for ApplicationManifest.xml settings values.
// xd:change -> match -> @Value is for ApplicationManifest.xml's config override sections and Settings.xml's settings values.
// xd:change -> match -> @EntryPointType is for Polcies node.
// xd:remove -> remove enables bringing over existing elements from source config (current) - like for plugins - to the target config (latest).
if (mergeExistingNodes)
{
xdoc.Root.Descendants(xd + "remove").Remove();
}
xdoc.Root.Descendants(xd + "change")
.Where(
n =>
n.Attribute("match").Value == "@DefaultValue" ||
n.Attribute("match").Value == "@Value" ||
n.Attribute("match").Value == "@EntryPointType")?.Remove();
xdoc.Save(diffGramFilePath);
PatchXml(currentVersionFilePath, diffGramFilePath, patchedFilePath);
}
private static void GenerateXmlDiffGram(string originalFile, string newFile, ref XmlWriter diffGramWriter)
{
var xmldiff = new XmlDiff(XmlDiffOptions.IgnoreNamespaces | XmlDiffOptions.IgnorePrefixes | XmlDiffOptions.IgnorePI);
if (xmldiff.Compare(originalFile, newFile, false, diffGramWriter))
{
diffGramWriter.WriteRaw(string.Empty);
}
diffGramWriter.Close();
}
private static void PatchXml(string originalFile, string diffGramFile, string outputFile)
{
var sourceDoc = new XmlDocument(new NameTable());
sourceDoc.Load(originalFile);
using (var diffgramReader = new XmlTextReader(diffGramFile))
{
var xmlpatch = new XmlPatch();
xmlpatch.Patch(sourceDoc, diffgramReader);
diffgramReader.Close();
}
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Entitize,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
CheckCharacters = true,
Indent = true,
DoNotEscapeUriAttributes = true,
NewLineOnAttributes = false,
};
using (var output = XmlWriter.Create(outputFile, settings))
{
sourceDoc.Save(output);
output.Close();
}
File.Delete(diffGramFile);
}
}
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Xml;
using Microsoft.XmlDiffPatch;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Linq;
namespace DiffPatchXmlSF
{
internal class Program
{
private static void Main(string[] args)
{
// Help..
if (args.Length == 1 && args[0] == "?")
{
Console.WriteLine(
"\nThis utility takes 2 required unnamed parameters, [currentXmlFileFullPath] and [latestXmlFileFullPath], and two optional parameters, [outputFileFullPath], [mergeExistingNodes].\n" +
"The first two parameters should be different versions of the *same* configuration file, where the current version is the one you want to patch/merge into the latest version (v1.0 -> v2.0, etc).\n" +
"The patch preserves the current version's settings values for elements/attributes that also exist in the latest version.\n" +
"If the optional [outputFileFullPath] arg is not provided, then the patched file name will be [latestXmlFileFullPath] appended with \"_patched\" " +
"preceding the file extension.\n\n" +
"**Note, if you have observer plugins, then you must supply true for [mergeExistingNodes] as the last argument to pull over your plugin settings as part of the merge.**.\n\n" +
"Example:\n\n" +
"DiffPatchXml \"C:\\repos\\FO\\3.1.26\\configs\\ApplicationManifest.xml\" \"C:\\repos\\FO\\3.2.6\\configs\\ApplicationManifest.xml\"\n");
return;
}
if (args.Length == 0 || args.Length < 2)
{
Console.WriteLine("Please pass the right parameters (2), e.g.,\n\n\t DiffPatchXml [currentXmlFileFullPath] [latestXmlFileFullPath]");
return;
}
if (!File.Exists(args[0]) || !File.Exists(args[1]))
{
Console.WriteLine("Supplied xml configuration files must exist.");
return;
}
string currentFileVersionPath = args[0];
string latestFileVersionPath = args[1];
try
{
var currentXml = XDocument.Load(currentFileVersionPath);
var latestXml = XDocument.Load(latestFileVersionPath);
currentXml = null;
latestXml = null;
}
catch (XmlException)
{
Console.WriteLine("Only XML is supported.");
return;
}
string diffgramFilePath = Path.GetTempFileName();
string patchedFilePath = Path.Combine(Path.GetDirectoryName(latestFileVersionPath), Path.GetFileNameWithoutExtension(latestFileVersionPath) + "_patched.xml");
bool mergeExistingNodes = false;
if (args.Length == 3 && !bool.TryParse(args[2], out mergeExistingNodes))
{
patchedFilePath = args[2];
}
else if (args.Length == 4)
{
_ = bool.TryParse(args[3], out mergeExistingNodes);
patchedFilePath = args[2];
}
DiffPatchXmlFiles(currentFileVersionPath, latestFileVersionPath, diffgramFilePath, patchedFilePath, mergeExistingNodes);
}
private static void DiffPatchXmlFiles(string currentVersionFilePath, string latestVersionFilePath, string diffGramFilePath, string patchedFilePath, bool mergeExistingNodes = false)
{
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Entitize,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
CheckCharacters = true,
Indent = true,
DoNotEscapeUriAttributes = true,
NewLineOnAttributes = false
};
XmlWriter output = null;
try
{
output = XmlWriter.Create(diffGramFilePath, settings);
GenerateXmlDiffGram(currentVersionFilePath, latestVersionFilePath, ref output);
}
finally
{
output.Dispose();
}
/* Remove changed values from old configs to support carry over to new version, which generally (not always) may have new elements.
This enables a master config's values to be preserved across app config upgrades of a Service Fabric app's base configuration (AppManifest and Settings).
Based on https://stackoverflow.com/questions/14341490/programmatic-xml-diff-merge-in-c-sharp */
XNamespace xd = "http://schemas.microsoft.com/xmltools/2002/xmldiff";
var xdoc = XDocument.Load(diffGramFilePath);
// xd:change -> match -> @DefaultValue is for ApplicationManifest.xml settings values.
// xd:change -> match -> @Value is for ApplicationManifest.xml's config override sections and Settings.xml's settings values.
// xd:change -> match -> @EntryPointType is for Polcies node.
// xd:remove -> remove enables bringing over existing elements from source config (current) - like for plugins - to the target config (latest).
if (mergeExistingNodes)
{
xdoc.Root.Descendants(xd + "remove").Remove();
}
xdoc.Root.Descendants(xd + "change")
.Where(
n =>
n.Attribute("match").Value == "@DefaultValue" ||
n.Attribute("match").Value == "@Value" ||
n.Attribute("match").Value == "@EntryPointType")?.Remove();
xdoc.Save(diffGramFilePath);
PatchXml(currentVersionFilePath, diffGramFilePath, patchedFilePath);
}
private static void GenerateXmlDiffGram(string originalFile, string newFile, ref XmlWriter diffGramWriter)
{
var xmldiff = new XmlDiff(XmlDiffOptions.IgnoreNamespaces | XmlDiffOptions.IgnorePrefixes | XmlDiffOptions.IgnorePI);
if (xmldiff.Compare(originalFile, newFile, false, diffGramWriter))
{
diffGramWriter.WriteRaw(string.Empty);
}
diffGramWriter.Close();
}
private static void PatchXml(string originalFile, string diffGramFile, string outputFile)
{
var sourceDoc = new XmlDocument(new NameTable());
sourceDoc.Load(originalFile);
using (var diffgramReader = new XmlTextReader(diffGramFile))
{
var xmlpatch = new XmlPatch();
xmlpatch.Patch(sourceDoc, diffgramReader);
diffgramReader.Close();
}
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Entitize,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
CheckCharacters = true,
Indent = true,
DoNotEscapeUriAttributes = true,
NewLineOnAttributes = false,
};
using (var output = XmlWriter.Create(outputFile, settings))
{
sourceDoc.Save(output);
output.Close();
}
File.Delete(diffGramFile);
}
}
}

Просмотреть файл

@ -1,68 +1,68 @@
## FabricObserver Extensibility Library 3.2.5
#### This library requires SF Runtime >= 9.0 (SDK 6.0.1017 at least) and targets .NET 6.
This .NET 6 library is for building FabricObserver plugins, which are custom observers that extend FabricObserver's capabilities to match your needs. Each plugin is managed like a first class observer.
### How to implement an observer plugin using FO's extensibility model
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the target net SDK version that FabricObserver is built for.
2. Install the latest Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps into your plugin project.
3. Write an observer plugin!
### Steps
- Create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
```C#
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
```
- Implement ObserverBase's two abstract functions:
```C#
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
```
- Create a [PluginTypeName]Startup.cs file
```C#
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
```
- Build, put the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll. Note that if FabricObserver already employs the same version of dependency dll,
then you can omit adding the dependency manually.
- Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file)
Update ApplicationManifest.xml with Parameters if you want to support Versionless Application Parameter-only Upgrades for your plugin.
## FabricObserver Extensibility Library 3.2.6
#### This library requires SF Runtime >= 9.0 (SDK 6.0.1017 at least) and targets .NET 6.
This .NET 6 library is for building FabricObserver plugins, which are custom observers that extend FabricObserver's capabilities to match your needs. Each plugin is managed like a first class observer.
### How to implement an observer plugin using FO's extensibility model
1. Create a new .NET core library project. You should target net6.0 in your csproj because that is the target net SDK version that FabricObserver is built for.
2. Install the latest Microsoft.ServiceFabricApps.FabricObserver.Extensibility nupkg from https://www.nuget.org/profiles/ServiceFabricApps into your plugin project.
3. Write an observer plugin!
### Steps
- Create a new class file, MyObserver.cs.
This is the required signature for your plugin's constructor:
```C#
// FO will provide (and manage) both the FabricClient instance and StatelessServiceContext instance during startup.
public MyObserver(FabricClient fabricClient, StatelessServiceContext context) : base(fabricClient, context)
{
}
```
- Implement ObserverBase's two abstract functions:
```C#
public override Task ObserveAsync()
{
}
public override Task ReportAsync()
{
}
```
- Create a [PluginTypeName]Startup.cs file
```C#
using System.Fabric;
using FabricObserver;
using FabricObserver.Observers;
using Microsoft.Extensions.DependencyInjection;
[assembly: FabricObserverStartup(typeof(MyObserverStartup))]
namespace FabricObserver.Observers
{
public class MyObserverStartup : IFabricObserverStartup
{
public void ConfigureServices(IServiceCollection services, FabricClient fabricClient, StatelessServiceContext context)
{
services.AddScoped(typeof(ObserverBase), s => new MyObserver(fabricClient, context));
}
}
}
```
- Build, put the output dll and *ALL* of its dependencies, both managed and native (this is *very* important), into the Config/Data/Plugins folder in FabricObserver/PackageRoot.
You can place your plugin dll and all of its dependencies in its own folder under the Plugins directory (useful if you have multiple plugins).
Again, ALL plugin dll dependencies (and their dependencies, if any) need to live in the *same* folder as the plugin dll. Note that if FabricObserver already employs the same version of dependency dll,
then you can omit adding the dependency manually.
- Add a new config section for your observer in FabricObserver/PackageRoot/Config/Settings.xml (see example at bottom of that file)
Update ApplicationManifest.xml with Parameters if you want to support Versionless Application Parameter-only Upgrades for your plugin.
- Ship it! (Well, test it first =)

Просмотреть файл

@ -1,91 +1,91 @@
## FabricObserver 3.2.5
#### This version requires SF Runtime >= 9.0 and targets .NET 6. .NET Core 3.1 is no longer supported.
[**FabricObserver (FO)**](https://github.com/microsoft/service-fabric-observer) is a complete implementation of a production-ready, generic resource usage watchdog service written as a stateless, singleton Service Fabric .NET 6 application that
1. Monitors a broad range of machine resources that tend to be very important to all Service Fabric applications, like disk space consumption, CPU use, memory use, endpoint availability, ephemeral TCP port use, and app/cluster certificate health out-of-the-box.
2. Runs on multiple versions of Windows Server and Ubuntu 18.04
3. Provides [an easy-to-use extensibility model](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md) for creating [custom Observers](https://github.com/microsoft/service-fabric-observer/blob/main/SampleObserverPlugin) out of band (so, you don't need to clone the repo to build an Observer). See [ContainerObserver](https://github.com/GitTorre/ContainerObserver) for a complete plugin impl that extends FO with SF container app resource monitoring and alerting (note that this observer is built into FO as of version 3.1.17).
4. Supports [Configuration Setting Application Updates](/Documentation/Using.md#parameterUpdates) for any observer for any supported setting.
5. Is actively developed completely in the open. The latest code (generally in flight and not meant for production) lives in the develop branch. It is highly recommended that you only deploy code built from the main branch into your production clusters.
> FabricObserver targets SF runtime versions 9 and higher.
FO is a Stateless Service Fabric Application composed of a single service that runs on every node in your cluster, so it can be deployed and run alongside your applications without any changes to them. Each FO service instance knows nothing about other FO instances in the cluster, by design.
```If you run your apps on Service Fabric, then you should definitely consider deploying FabricObserver to all of your clusters (Test, Staging, Production).```
## Using FabricObserver
To quickly learn how to use FO, please see the **[simple scenario-based examples](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Using.md)**.
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FOClusterView.png "Cluster View App Warning UI")
## How it works
Application Level Warnings:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/AppWarnClusterView.png "Cluster View App Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/AppObsWarn.png "AppObserver Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/ContainerObserver.png "ContainerObserver Warning UI")
Node Level Warnings:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/DiskObsWarn.png "DiskObserver Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FODiskNodeObs.png "Multiple Observers Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FODiskNodeOkClears.png "Multiple Health Event OK Clearing UI")
Node Level Machine Info:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FONodeDetails.png "Node Details UI")
When FabricObserver gracefully exits or updates, it will clear all of the health events it created.
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/EventClearOnUpdateExit.png "All Health Event Clearing UI")
FabricObserver comes with a number of Observers that run out-of-the-box. Observers are specialized objects that monitor, point in time, specific resources in use by user service processes, SF system service processes, containers, virtual/physical machines. They emit Service Fabric health reports, diagnostic telemetry and ETW events, then go away until the next round of monitoring. The resource metric thresholds supplied in the configurations of the built-in observers must be set to match your specific monitoring and alerting needs. These settings are housed in [Settings.xml](/FabricObserver/PackageRoot/Config/Settings.xml) and [ApplicationManifest.xml](/FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml). The default settings are useful without any modifications, but you should design your resource usage thresholds according to your specific needs.
When a Warning threshold is reached or exceeded, an observer will send a Health Report to Service Fabric's Health management system (either as a Node or Application Health Report, depending on the observer). This Warning state and related reports are viewable in SFX, the Service Fabric EventStore, and Azure's Application Insights/LogAnalytics/ETW, if enabled and configured.
Most observers will remove the Warning state in cases where the issue is transient, but others will maintain a long-running Warning for applications/services/nodes/security problems observed in the cluster. For example, high CPU usage above the user-assigned threshold for a VM or App/Service will put a Node into Warning State (NodeObserver) or Application Warning state (AppObserver), for example, but will soon go back to Healthy if it is a transient spike or after you mitigate the specific problem :-). An expiring certificate Warning from CertificateObsever, however, will remain until you update your application's certificates (Cluster certificates are already monitored by the SF runtime. This is not the case for Application certificates, so use CertificateObserver for this, if necessary).
[Read more about Service Fabric Health Reports](https://docs.microsoft.com/azure/service-fabric/service-fabric-report-health)
FO ships with both an Azure ApplicationInsights and Azure LogAnalytics telemetry implementation. Other providers can be used by implementing the [ITelemetryProvider interface](https://github.com/microsoft/service-fabric-observer/blob/main/FabricObserver.Extensibility/Interfaces/ITelemetryProvider.cs).
For more information about **the design of FabricObserver**, please see the [Design readme](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Design.md).
***Note: By default, FO runs as NetworkUser on Windows and sfappsuser on Linux. If you want to monitor SF service processes that run as elevated (System) on Windows, then you must also run FO as System on Windows. There is no reason to run as root on Linux under any circumstances (see the Capabilities binaries implementations, which allow for FO to run as sfappsuser and successfully execute specific commands that require elevated privilege).***
For Linux deployments, we have ensured that FO will work as expected as normal user (non-root user). In order for us to do this, we had to implement a setup script that sets [Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) on three proxy binaries which can only run specific commands as root.
## Configuration Change Support
When a new version of FabricObserver ships, often (not always) there will be new configuration settings, which requires customers to manually update the latest ApplicationManifest.xml and Settings.xml files with their preferred/established settings (current). In order
to remove this manual step when upgrading, we wrote a simple tool that will diff/patch FO config (XML-only) automatically, which will be quite useful in devops workflows. Please try out [XmlDiffPatchSF](https://github.com/GitTorre/XmlDiffPatchSF) and use it in your pipelines or other build automation systems. It should save you some time.
## Observer Model
FO is composed of Observer objects (instance types) that are designed to observe, record, and report on several machine-level environmental conditions inside a Windows or Linux (Ubuntu) VM hosting a Service Fabric node.
Here are the current observers and what they monitor:
| Resource | Observer |
| --- | --- |
| Application (services) resource usage health monitoring across CPU, File Handles, Memory, Ports (TCP), Threads | AppObserver |
| Looks for dmp and zip files in AppObserver's MemoryDumps folder, compresses (if necessary) and uploads them to your specified Azure storage account (blob only, AppObserver only, and still Windows only in this version of FO) | AzureStorageUploadObserver |
| Application (user) and cluster certificate health monitoring | CertificateObserver |
| Container resource usage health monitoring across CPU and Memory | ContainerObserver |
| Disk (local storage disk health/availability, space usage, IO) | DiskObserver |
| SF System Services resource usage health monitoring across CPU, File Handles, Memory, Ports (TCP), Threads | FabricSystemObserver |
| Networking - general health and monitoring of availability of user-specified, per-app endpoints | NetworkObserver |
| CPU/Memory/File Handles(Linux)/Firewalls(Windows)/TCP Ports usage at machine level | NodeObserver |
| OS/Hardware - OS install date, OS health status, list of hot fixes, hardware configuration, AutoUpdate configuration, Ephemeral TCP port range, TCP ports in use, memory and disk space usage | OSObserver |
| Service Fabric Configuration information | SFConfigurationObserver |
| **Another resource you find important** | **Observer [that you implement](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md)** |
To learn more about the current Observers and their configuration, please see the [Observers readme](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Observers.md).
```
Just observe it.
## FabricObserver 3.2.6
#### This version requires SF Runtime >= 9.0 and targets .NET 6. .NET Core 3.1 is no longer supported.
[**FabricObserver (FO)**](https://github.com/microsoft/service-fabric-observer) is a complete implementation of a production-ready, generic resource usage watchdog service written as a stateless, singleton Service Fabric .NET 6 application that
1. Monitors a broad range of machine resources that tend to be very important to all Service Fabric applications, like disk space consumption, CPU use, memory use, endpoint availability, ephemeral TCP port use, and app/cluster certificate health out-of-the-box.
2. Runs on multiple versions of Windows Server and Ubuntu 18.04
3. Provides [an easy-to-use extensibility model](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md) for creating [custom Observers](https://github.com/microsoft/service-fabric-observer/blob/main/SampleObserverPlugin) out of band (so, you don't need to clone the repo to build an Observer). See [ContainerObserver](https://github.com/GitTorre/ContainerObserver) for a complete plugin impl that extends FO with SF container app resource monitoring and alerting (note that this observer is built into FO as of version 3.1.17).
4. Supports [Configuration Setting Application Updates](/Documentation/Using.md#parameterUpdates) for any observer for any supported setting.
5. Is actively developed completely in the open. The latest code (generally in flight and not meant for production) lives in the develop branch. It is highly recommended that you only deploy code built from the main branch into your production clusters.
> FabricObserver targets SF runtime versions 9 and higher.
FO is a Stateless Service Fabric Application composed of a single service that runs on every node in your cluster, so it can be deployed and run alongside your applications without any changes to them. Each FO service instance knows nothing about other FO instances in the cluster, by design.
```If you run your apps on Service Fabric, then you should definitely consider deploying FabricObserver to all of your clusters (Test, Staging, Production).```
## Using FabricObserver
To quickly learn how to use FO, please see the **[simple scenario-based examples](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Using.md)**.
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FOClusterView.png "Cluster View App Warning UI")
## How it works
Application Level Warnings:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/AppWarnClusterView.png "Cluster View App Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/AppObsWarn.png "AppObserver Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/ContainerObserver.png "ContainerObserver Warning UI")
Node Level Warnings:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/DiskObsWarn.png "DiskObserver Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FODiskNodeObs.png "Multiple Observers Warning UI")
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FODiskNodeOkClears.png "Multiple Health Event OK Clearing UI")
Node Level Machine Info:
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/FONodeDetails.png "Node Details UI")
When FabricObserver gracefully exits or updates, it will clear all of the health events it created.
![alt text](https://raw.githubusercontent.com/microsoft/service-fabric-observer/main/Documentation/Images/EventClearOnUpdateExit.png "All Health Event Clearing UI")
FabricObserver comes with a number of Observers that run out-of-the-box. Observers are specialized objects that monitor, point in time, specific resources in use by user service processes, SF system service processes, containers, virtual/physical machines. They emit Service Fabric health reports, diagnostic telemetry and ETW events, then go away until the next round of monitoring. The resource metric thresholds supplied in the configurations of the built-in observers must be set to match your specific monitoring and alerting needs. These settings are housed in [Settings.xml](/FabricObserver/PackageRoot/Config/Settings.xml) and [ApplicationManifest.xml](/FabricObserverApp/ApplicationPackageRoot/ApplicationManifest.xml). The default settings are useful without any modifications, but you should design your resource usage thresholds according to your specific needs.
When a Warning threshold is reached or exceeded, an observer will send a Health Report to Service Fabric's Health management system (either as a Node or Application Health Report, depending on the observer). This Warning state and related reports are viewable in SFX, the Service Fabric EventStore, and Azure's Application Insights/LogAnalytics/ETW, if enabled and configured.
Most observers will remove the Warning state in cases where the issue is transient, but others will maintain a long-running Warning for applications/services/nodes/security problems observed in the cluster. For example, high CPU usage above the user-assigned threshold for a VM or App/Service will put a Node into Warning State (NodeObserver) or Application Warning state (AppObserver), for example, but will soon go back to Healthy if it is a transient spike or after you mitigate the specific problem :-). An expiring certificate Warning from CertificateObsever, however, will remain until you update your application's certificates (Cluster certificates are already monitored by the SF runtime. This is not the case for Application certificates, so use CertificateObserver for this, if necessary).
[Read more about Service Fabric Health Reports](https://docs.microsoft.com/azure/service-fabric/service-fabric-report-health)
FO ships with both an Azure ApplicationInsights and Azure LogAnalytics telemetry implementation. Other providers can be used by implementing the [ITelemetryProvider interface](https://github.com/microsoft/service-fabric-observer/blob/main/FabricObserver.Extensibility/Interfaces/ITelemetryProvider.cs).
For more information about **the design of FabricObserver**, please see the [Design readme](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Design.md).
***Note: By default, FO runs as NetworkUser on Windows and sfappsuser on Linux. If you want to monitor SF service processes that run as elevated (System) on Windows, then you must also run FO as System on Windows. There is no reason to run as root on Linux under any circumstances (see the Capabilities binaries implementations, which allow for FO to run as sfappsuser and successfully execute specific commands that require elevated privilege).***
For Linux deployments, we have ensured that FO will work as expected as normal user (non-root user). In order for us to do this, we had to implement a setup script that sets [Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) on three proxy binaries which can only run specific commands as root.
## Configuration Change Support
When a new version of FabricObserver ships, often (not always) there will be new configuration settings, which requires customers to manually update the latest ApplicationManifest.xml and Settings.xml files with their preferred/established settings (current). In order
to remove this manual step when upgrading, we wrote a simple tool that will diff/patch FO config (XML-only) automatically, which will be quite useful in devops workflows. Please try out [XmlDiffPatchSF](https://github.com/GitTorre/XmlDiffPatchSF) and use it in your pipelines or other build automation systems. It should save you some time.
## Observer Model
FO is composed of Observer objects (instance types) that are designed to observe, record, and report on several machine-level environmental conditions inside a Windows or Linux (Ubuntu) VM hosting a Service Fabric node.
Here are the current observers and what they monitor:
| Resource | Observer |
| --- | --- |
| Application (services) resource usage health monitoring across CPU, File Handles, Memory, Ports (TCP), Threads | AppObserver |
| Looks for dmp and zip files in AppObserver's MemoryDumps folder, compresses (if necessary) and uploads them to your specified Azure storage account (blob only, AppObserver only, and still Windows only in this version of FO) | AzureStorageUploadObserver |
| Application (user) and cluster certificate health monitoring | CertificateObserver |
| Container resource usage health monitoring across CPU and Memory | ContainerObserver |
| Disk (local storage disk health/availability, space usage, IO) | DiskObserver |
| SF System Services resource usage health monitoring across CPU, File Handles, Memory, Ports (TCP), Threads | FabricSystemObserver |
| Networking - general health and monitoring of availability of user-specified, per-app endpoints | NetworkObserver |
| CPU/Memory/File Handles(Linux)/Firewalls(Windows)/TCP Ports usage at machine level | NodeObserver |
| OS/Hardware - OS install date, OS health status, list of hot fixes, hardware configuration, AutoUpdate configuration, Ephemeral TCP port range, TCP ports in use, memory and disk space usage | OSObserver |
| Service Fabric Configuration information | SFConfigurationObserver |
| **Another resource you find important** | **Observer [that you implement](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Plugins.md)** |
To learn more about the current Observers and their configuration, please see the [Observers readme](https://github.com/microsoft/service-fabric-observer/blob/main/Documentation/Observers.md).
```
Just observe it.
```