diff --git a/CMP.ServiceFabric.Logging.sln b/CMP.ServiceFabric.Logging.sln index 0a97664..4899a69 100644 --- a/CMP.ServiceFabric.Logging.sln +++ b/CMP.ServiceFabric.Logging.sln @@ -5,20 +5,73 @@ VisualStudioVersion = 16.0.29411.108 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CMP.ServiceFabric.Logging", "CMP.ServiceFabric.Logging\CMP.ServiceFabric.Logging.csproj", "{CB41048B-A0EF-4712-91D0-B2716FE76E72}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleSample", "samples\ConsoleSample\ConsoleSample.csproj", "{A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}" +EndProject +Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "Sample", "samples\Sample\Sample.sfproj", "{75DB17CC-CC97-4606-8136-773FF9760172}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SfWeb", "samples\SfWeb\SfWeb.csproj", "{2E4FFB18-5AC5-4D86-802B-DE13105EAC54}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServiceFabric", "ServiceFabric", "{27DCEE15-6A9C-4D05-A8AF-D428008322AC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SfWorker", "samples\SfWorker\SfWorker.csproj", "{5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}" +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 {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Debug|x64.Build.0 = Debug|Any CPU {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Release|Any CPU.Build.0 = Release|Any CPU + {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Release|x64.ActiveCfg = Release|Any CPU + {CB41048B-A0EF-4712-91D0-B2716FE76E72}.Release|x64.Build.0 = Release|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Debug|x64.Build.0 = Debug|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Release|Any CPU.Build.0 = Release|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Release|x64.ActiveCfg = Release|Any CPU + {A75E5CC0-6614-4A3B-95FD-C58B7BAEC4CA}.Release|x64.Build.0 = Release|Any CPU + {75DB17CC-CC97-4606-8136-773FF9760172}.Debug|Any CPU.ActiveCfg = Debug|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Debug|x64.ActiveCfg = Debug|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Debug|x64.Build.0 = Debug|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Debug|x64.Deploy.0 = Debug|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Release|Any CPU.ActiveCfg = Release|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Release|x64.ActiveCfg = Release|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Release|x64.Build.0 = Release|x64 + {75DB17CC-CC97-4606-8136-773FF9760172}.Release|x64.Deploy.0 = Release|x64 + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Debug|x64.ActiveCfg = Debug|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Debug|x64.Build.0 = Debug|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Release|Any CPU.Build.0 = Release|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Release|x64.ActiveCfg = Release|Any CPU + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54}.Release|x64.Build.0 = Release|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Debug|x64.ActiveCfg = Debug|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Debug|x64.Build.0 = Debug|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Release|Any CPU.Build.0 = Release|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Release|x64.ActiveCfg = Release|Any CPU + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {75DB17CC-CC97-4606-8136-773FF9760172} = {27DCEE15-6A9C-4D05-A8AF-D428008322AC} + {2E4FFB18-5AC5-4D86-802B-DE13105EAC54} = {27DCEE15-6A9C-4D05-A8AF-D428008322AC} + {5CF26A45-55D9-4FA5-9BF6-365C6B3FA622} = {27DCEE15-6A9C-4D05-A8AF-D428008322AC} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8C23C15D-BAED-427D-833E-EA3794ECC1B9} EndGlobalSection diff --git a/CMP.ServiceFabric.Logging/CMP.ServiceFabric.Logging.csproj b/CMP.ServiceFabric.Logging/CMP.ServiceFabric.Logging.csproj index 483e1ec..434b8cc 100644 --- a/CMP.ServiceFabric.Logging/CMP.ServiceFabric.Logging.csproj +++ b/CMP.ServiceFabric.Logging/CMP.ServiceFabric.Logging.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.1.5 + 0.1.6 alpha CMP.ServiceFabric.Logging CDON diff --git a/CMP.ServiceFabric.Logging/SuccessfulDependencyFilter.cs b/CMP.ServiceFabric.Logging/SuccessfulDependencyFilter.cs new file mode 100644 index 0000000..bbd79ec --- /dev/null +++ b/CMP.ServiceFabric.Logging/SuccessfulDependencyFilter.cs @@ -0,0 +1,31 @@ +using Microsoft.ApplicationInsights.Channel; +using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.ApplicationInsights.Extensibility; + +namespace CMP.ServiceFabric.Logging +{ + public class SuccessfulDependencyFilter : ITelemetryProcessor + { + private ITelemetryProcessor Next { get; set; } + + public SuccessfulDependencyFilter(ITelemetryProcessor next) + { + this.Next = next; + } + + public void Process(ITelemetry item) + { + if (!OKtoSend(item)) { return; } + + this.Next.Process(item); + } + + private bool OKtoSend(ITelemetry item) + { + var dependency = item as DependencyTelemetry; + if (dependency == null) return true; + + return dependency.Success != true; + } + } +} diff --git a/samples/ConsoleSample/ConsoleSample.csproj b/samples/ConsoleSample/ConsoleSample.csproj new file mode 100644 index 0000000..765c888 --- /dev/null +++ b/samples/ConsoleSample/ConsoleSample.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + diff --git a/samples/ConsoleSample/Program.cs b/samples/ConsoleSample/Program.cs new file mode 100644 index 0000000..6d7d068 --- /dev/null +++ b/samples/ConsoleSample/Program.cs @@ -0,0 +1,36 @@ +using Serilog; +using System; +using CMP.ServiceFabric.Logging; +using Microsoft.ApplicationInsights.Extensibility; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace ConsoleSample +{ + class Program + { + static void Main(string[] args) + { + var instrumentationKey = args.First(); + + var serviceProvider = new ServiceCollection() + .AddApplicationInsightsTelemetryWorkerService(instrumentationKey) + .AddApplicationInsightsTelemetryProcessor() + .BuildServiceProvider(); + + var telemetryConfiguration = serviceProvider.GetRequiredService(); + + Log.Logger = new LoggerConfiguration() + .DefaultCmp(telemetryConfiguration, "development") + .CreateLogger(); + + var coreLogger = telemetryConfiguration.ConfigureLogging(Log.Logger, "ConsoleSample"); + //NOTE in SF: coreLogger = context.ConfigureLogging(telemetryConfiguration, Log.Logger, "ConsoleSample"); + + coreLogger.LogInformation("Hello world"); + Console.WriteLine("Hello World! - press a key to end."); + Console.ReadLine(); + } + } +} diff --git a/samples/Sample/ApplicationPackageRoot/ApplicationManifest.xml b/samples/Sample/ApplicationPackageRoot/ApplicationManifest.xml new file mode 100644 index 0000000..0a80377 --- /dev/null +++ b/samples/Sample/ApplicationPackageRoot/ApplicationManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Sample/ApplicationParameters/Cloud.xml b/samples/Sample/ApplicationParameters/Cloud.xml new file mode 100644 index 0000000..c0a013c --- /dev/null +++ b/samples/Sample/ApplicationParameters/Cloud.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/Sample/ApplicationParameters/Local.1Node.xml b/samples/Sample/ApplicationParameters/Local.1Node.xml new file mode 100644 index 0000000..a6e6b31 --- /dev/null +++ b/samples/Sample/ApplicationParameters/Local.1Node.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/Sample/ApplicationParameters/Local.5Node.xml b/samples/Sample/ApplicationParameters/Local.5Node.xml new file mode 100644 index 0000000..a6e6b31 --- /dev/null +++ b/samples/Sample/ApplicationParameters/Local.5Node.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/Sample/PublishProfiles/Cloud.xml b/samples/Sample/PublishProfiles/Cloud.xml new file mode 100644 index 0000000..a88f728 --- /dev/null +++ b/samples/Sample/PublishProfiles/Cloud.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/samples/Sample/PublishProfiles/Local.1Node.xml b/samples/Sample/PublishProfiles/Local.1Node.xml new file mode 100644 index 0000000..6e1403e --- /dev/null +++ b/samples/Sample/PublishProfiles/Local.1Node.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/samples/Sample/PublishProfiles/Local.5Node.xml b/samples/Sample/PublishProfiles/Local.5Node.xml new file mode 100644 index 0000000..f42d759 --- /dev/null +++ b/samples/Sample/PublishProfiles/Local.5Node.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/samples/Sample/Sample.sfproj b/samples/Sample/Sample.sfproj new file mode 100644 index 0000000..5fdaecc --- /dev/null +++ b/samples/Sample/Sample.sfproj @@ -0,0 +1,50 @@ + + + + + 75db17cc-cc97-4606-8136-773ff9760172 + 2.5 + 1.5 + 1.6.9 + v4.7.2 + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + http://{MachineName}:{ServicePort}/ + + + + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets + + + + + + + + \ No newline at end of file diff --git a/samples/Sample/Scripts/Deploy-FabricApplication.ps1 b/samples/Sample/Scripts/Deploy-FabricApplication.ps1 new file mode 100644 index 0000000..8e87d30 --- /dev/null +++ b/samples/Sample/Scripts/Deploy-FabricApplication.ps1 @@ -0,0 +1,273 @@ +<# +.SYNOPSIS +Deploys a Service Fabric application type to a cluster. + +.DESCRIPTION +This script deploys a Service Fabric application type to a cluster. It is invoked by Visual Studio when deploying a Service Fabric Application project. + +.NOTES +WARNING: This script file is invoked by Visual Studio. Its parameters must not be altered but its logic can be customized as necessary. + +.PARAMETER PublishProfileFile +Path to the file containing the publish profile. + +.PARAMETER ApplicationPackagePath +Path to the folder of the packaged Service Fabric application. + +.PARAMETER DeployOnly +Indicates that the Service Fabric application should not be created or upgraded after registering the application type. + +.PARAMETER ApplicationParameter +Hashtable of the Service Fabric application parameters to be used for the application. + +.PARAMETER UnregisterUnusedApplicationVersionsAfterUpgrade +Indicates whether to unregister any unused application versions that exist after an upgrade is finished. + +.PARAMETER OverrideUpgradeBehavior +Indicates the behavior used to override the upgrade settings specified by the publish profile. +'None' indicates that the upgrade settings will not be overridden. +'ForceUpgrade' indicates that an upgrade will occur with default settings, regardless of what is specified in the publish profile. +'VetoUpgrade' indicates that an upgrade will not occur, regardless of what is specified in the publish profile. + +.PARAMETER UseExistingClusterConnection +Indicates that the script should make use of an existing cluster connection that has already been established in the PowerShell session. The cluster connection parameters configured in the publish profile are ignored. + +.PARAMETER OverwriteBehavior +Overwrite Behavior if an application exists in the cluster with the same name. Available Options are Never, Always, SameAppTypeAndVersion. This setting is not applicable when upgrading an application. +'Never' will not remove the existing application. This is the default behavior. +'Always' will remove the existing application even if its Application type and Version is different from the application being created. +'SameAppTypeAndVersion' will remove the existing application only if its Application type and Version is same as the application being created. + +.PARAMETER SkipPackageValidation +Switch signaling whether the package should be validated or not before deployment. + +.PARAMETER SecurityToken +A security token for authentication to cluster management endpoints. Used for silent authentication to clusters that are protected by Azure Active Directory. + +.PARAMETER CopyPackageTimeoutSec +Timeout in seconds for copying application package to image store. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' + +Deploy the application using the default package location for a Debug build. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -DoNotCreateApplication + +Deploy the application but do not create the application instance. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -ApplicationParameter @{CustomParameter1='MyValue'; CustomParameter2='MyValue'} + +Deploy the application by providing values for parameters that are defined in the application manifest. +#> + +Param +( + [String] + $PublishProfileFile, + + [String] + $ApplicationPackagePath, + + [Switch] + $DeployOnly, + + [Hashtable] + $ApplicationParameter, + + [Boolean] + $UnregisterUnusedApplicationVersionsAfterUpgrade, + + [String] + [ValidateSet('None', 'ForceUpgrade', 'VetoUpgrade')] + $OverrideUpgradeBehavior = 'None', + + [Switch] + $UseExistingClusterConnection, + + [String] + [ValidateSet('Never','Always','SameAppTypeAndVersion')] + $OverwriteBehavior = 'Never', + + [Switch] + $SkipPackageValidation, + + [String] + $SecurityToken, + + [int] + $CopyPackageTimeoutSec, + + [int] + $RegisterApplicationTypeTimeoutSec +) + +function Read-XmlElementAsHashtable +{ + Param ( + [System.Xml.XmlElement] + $Element + ) + + $hashtable = @{} + if ($Element.Attributes) + { + $Element.Attributes | + ForEach-Object { + $boolVal = $null + if ([bool]::TryParse($_.Value, [ref]$boolVal)) { + $hashtable[$_.Name] = $boolVal + } + else { + $hashtable[$_.Name] = $_.Value + } + } + } + + return $hashtable +} + +function Read-PublishProfile +{ + Param ( + [ValidateScript({Test-Path $_ -PathType Leaf})] + [String] + $PublishProfileFile + ) + + $publishProfileXml = [Xml] (Get-Content $PublishProfileFile -Encoding UTF8) + $publishProfile = @{} + + $publishProfile.ClusterConnectionParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("ClusterConnectionParameters") + $publishProfile.UpgradeDeployment = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment") + $publishProfile.CopyPackageParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("CopyPackageParameters") + $publishProfile.RegisterApplicationParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("RegisterApplicationParameters") + + if ($publishProfileXml.PublishProfile.Item("UpgradeDeployment")) + { + $publishProfile.UpgradeDeployment.Parameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment").Item("Parameters") + if ($publishProfile.UpgradeDeployment["Mode"]) + { + $publishProfile.UpgradeDeployment.Parameters[$publishProfile.UpgradeDeployment["Mode"]] = $true + } + } + + $publishProfileFolder = (Split-Path $PublishProfileFile) + $publishProfile.ApplicationParameterFile = [System.IO.Path]::Combine($PublishProfileFolder, $publishProfileXml.PublishProfile.ApplicationParameterFile.Path) + + return $publishProfile +} + +$LocalFolder = (Split-Path $MyInvocation.MyCommand.Path) + +if (!$PublishProfileFile) +{ + $PublishProfileFile = "$LocalFolder\..\PublishProfiles\Local.xml" +} + +if (!$ApplicationPackagePath) +{ + $ApplicationPackagePath = "$LocalFolder\..\pkg\Release" +} + +$ApplicationPackagePath = Resolve-Path $ApplicationPackagePath + +$publishProfile = Read-PublishProfile $PublishProfileFile + +if (-not $UseExistingClusterConnection) +{ + $ClusterConnectionParameters = $publishProfile.ClusterConnectionParameters + if ($SecurityToken) + { + $ClusterConnectionParameters["SecurityToken"] = $SecurityToken + } + + try + { + [void](Connect-ServiceFabricCluster @ClusterConnectionParameters) + } + catch [System.Fabric.FabricObjectClosedException] + { + Write-Warning "Service Fabric cluster may not be connected." + throw + } +} + +$RegKey = "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" +$ModuleFolderPath = (Get-ItemProperty -Path $RegKey -Name FabricSDKPSModulePath).FabricSDKPSModulePath +Import-Module "$ModuleFolderPath\ServiceFabricSDK.psm1" + +$IsUpgrade = ($publishProfile.UpgradeDeployment -and $publishProfile.UpgradeDeployment.Enabled -and $OverrideUpgradeBehavior -ne 'VetoUpgrade') -or $OverrideUpgradeBehavior -eq 'ForceUpgrade' + +$PublishParameters = @{ + 'ApplicationPackagePath' = $ApplicationPackagePath + 'ApplicationParameterFilePath' = $publishProfile.ApplicationParameterFile + 'ApplicationParameter' = $ApplicationParameter + 'ErrorAction' = 'Stop' +} + +if ($publishProfile.CopyPackageParameters.CopyPackageTimeoutSec) +{ + $PublishParameters['CopyPackageTimeoutSec'] = $publishProfile.CopyPackageParameters.CopyPackageTimeoutSec +} + +if ($publishProfile.CopyPackageParameters.CompressPackage) +{ + $PublishParameters['CompressPackage'] = $publishProfile.CopyPackageParameters.CompressPackage +} + +if ($publishProfile.RegisterApplicationParameters.RegisterApplicationTypeTimeoutSec) +{ + $PublishParameters['RegisterApplicationTypeTimeoutSec'] = $publishProfile.RegisterApplicationParameters.RegisterApplicationTypeTimeoutSec +} + +# CopyPackageTimeoutSec parameter overrides the value from the publish profile +if ($CopyPackageTimeoutSec) +{ + $PublishParameters['CopyPackageTimeoutSec'] = $CopyPackageTimeoutSec +} + +# RegisterApplicationTypeTimeoutSec parameter overrides the value from the publish profile +if ($RegisterApplicationTypeTimeoutSec) +{ + $PublishParameters['RegisterApplicationTypeTimeoutSec'] = $RegisterApplicationTypeTimeoutSec +} + +if ($IsUpgrade) +{ + $Action = "RegisterAndUpgrade" + if ($DeployOnly) + { + $Action = "Register" + } + + $UpgradeParameters = $publishProfile.UpgradeDeployment.Parameters + + if ($OverrideUpgradeBehavior -eq 'ForceUpgrade') + { + # Warning: Do not alter these upgrade parameters. It will create an inconsistency with Visual Studio's behavior. + $UpgradeParameters = @{ UnmonitoredAuto = $true; Force = $true } + } + + $PublishParameters['Action'] = $Action + $PublishParameters['UpgradeParameters'] = $UpgradeParameters + $PublishParameters['UnregisterUnusedVersions'] = $UnregisterUnusedApplicationVersionsAfterUpgrade + + Publish-UpgradedServiceFabricApplication @PublishParameters +} +else +{ + $Action = "RegisterAndCreate" + if ($DeployOnly) + { + $Action = "Register" + } + + $PublishParameters['Action'] = $Action + $PublishParameters['OverwriteBehavior'] = $OverwriteBehavior + $PublishParameters['SkipPackageValidation'] = $SkipPackageValidation + + Publish-NewServiceFabricApplication @PublishParameters +} \ No newline at end of file diff --git a/samples/Sample/packages.config b/samples/Sample/packages.config new file mode 100644 index 0000000..a57e997 --- /dev/null +++ b/samples/Sample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/samples/SfWeb/PackageRoot/Config/Settings.xml b/samples/SfWeb/PackageRoot/Config/Settings.xml new file mode 100644 index 0000000..902c747 --- /dev/null +++ b/samples/SfWeb/PackageRoot/Config/Settings.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/samples/SfWeb/PackageRoot/ServiceManifest.xml b/samples/SfWeb/PackageRoot/ServiceManifest.xml new file mode 100644 index 0000000..722b00c --- /dev/null +++ b/samples/SfWeb/PackageRoot/ServiceManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + SfWeb.exe + CodePackage + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SfWeb/Program.cs b/samples/SfWeb/Program.cs new file mode 100644 index 0000000..cebab54 --- /dev/null +++ b/samples/SfWeb/Program.cs @@ -0,0 +1,48 @@ +using Microsoft.ApplicationInsights; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ServiceFabric.Services.Runtime; +using Serilog; +using System; +using System.Diagnostics; +using System.Threading; +using CMP.ServiceFabric.Logging; + +namespace SfWeb +{ + internal static class Program + { + private static void Main() + { + var telemetryConfiguration = TelemetryConfiguration.CreateDefault(); + telemetryConfiguration.InstrumentationKey = "key"; + + var telemetryClient = new TelemetryClient(telemetryConfiguration); + + Log.Logger = new LoggerConfiguration() + .DefaultCmp(telemetryConfiguration, "development") + .CreateLogger(); + + try + { + ServiceRuntime.RegisterServiceAsync("SfWebType", + context => + { + //TODO this only adds a initializer (SF) + //to the create core ILogger....(what about Log.Logger) + //and resolved ILogger (both) - this is not in IoC + context.ConfigureLogging(telemetryConfiguration, Log.Logger, "SfWebType"); + return new SfWeb(context); + }).GetAwaiter().GetResult(); + + ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(SfWeb).Name); + + Thread.Sleep(Timeout.Infinite); + } + catch (Exception e) + { + ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); + throw; + } + } + } +} diff --git a/samples/SfWeb/ServiceEventSource.cs b/samples/SfWeb/ServiceEventSource.cs new file mode 100644 index 0000000..8216f35 --- /dev/null +++ b/samples/SfWeb/ServiceEventSource.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Fabric; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Runtime; + +namespace SfWeb +{ + [EventSource(Name = "MyCompany-Sample-SfWeb")] + internal sealed class ServiceEventSource : EventSource + { + public static readonly ServiceEventSource Current = new ServiceEventSource(); + + static ServiceEventSource() + { + // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. + // This problem will be fixed in .NET Framework 4.6.2. + Task.Run(() => { }); + } + + // Instance constructor is private to enforce singleton semantics + private ServiceEventSource() : base() { } + + #region Keywords + // Event keywords can be used to categorize events. + // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). + // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. + public static class Keywords + { + public const EventKeywords Requests = (EventKeywords)0x1L; + public const EventKeywords ServiceInitialization = (EventKeywords)0x2L; + } + #endregion + + #region Events + // Define an instance method for each event you want to record and apply an [Event] attribute to it. + // The method name is the name of the event. + // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). + // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. + // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). + // Put [NonEvent] attribute on all methods that do not define an event. + // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx + + [NonEvent] + public void Message(string message, params object[] args) + { + if (this.IsEnabled()) + { + string finalMessage = string.Format(message, args); + Message(finalMessage); + } + } + + private const int MessageEventId = 1; + [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] + public void Message(string message) + { + if (this.IsEnabled()) + { + WriteEvent(MessageEventId, message); + } + } + + [NonEvent] + public void ServiceMessage(ServiceContext serviceContext, string message, params object[] args) + { + if (this.IsEnabled()) + { + + string finalMessage = string.Format(message, args); + ServiceMessage( + serviceContext.ServiceName.ToString(), + serviceContext.ServiceTypeName, + GetReplicaOrInstanceId(serviceContext), + serviceContext.PartitionId, + serviceContext.CodePackageActivationContext.ApplicationName, + serviceContext.CodePackageActivationContext.ApplicationTypeName, + serviceContext.NodeContext.NodeName, + finalMessage); + } + } + + // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. + // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. + // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. + private const int ServiceMessageEventId = 2; + [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] + private +#if UNSAFE + unsafe +#endif + void ServiceMessage( + string serviceName, + string serviceTypeName, + long replicaOrInstanceId, + Guid partitionId, + string applicationName, + string applicationTypeName, + string nodeName, + string message) + { +#if !UNSAFE + WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); +#else + const int numArgs = 8; + fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message) + { + EventData* eventData = stackalloc EventData[numArgs]; + eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) }; + eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) }; + eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) }; + eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) }; + eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) }; + eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) }; + eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) }; + eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) }; + + WriteEventCore(ServiceMessageEventId, numArgs, eventData); + } +#endif + } + + private const int ServiceTypeRegisteredEventId = 3; + [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] + public void ServiceTypeRegistered(int hostProcessId, string serviceType) + { + WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); + } + + private const int ServiceHostInitializationFailedEventId = 4; + [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] + public void ServiceHostInitializationFailed(string exception) + { + WriteEvent(ServiceHostInitializationFailedEventId, exception); + } + + // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. + // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, + // and other statistics. + private const int ServiceRequestStartEventId = 5; + [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] + public void ServiceRequestStart(string requestTypeName) + { + WriteEvent(ServiceRequestStartEventId, requestTypeName); + } + + private const int ServiceRequestStopEventId = 6; + [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] + public void ServiceRequestStop(string requestTypeName, string exception = "") + { + WriteEvent(ServiceRequestStopEventId, requestTypeName, exception); + } + #endregion + + #region Private methods + private static long GetReplicaOrInstanceId(ServiceContext context) + { + StatelessServiceContext stateless = context as StatelessServiceContext; + if (stateless != null) + { + return stateless.InstanceId; + } + + StatefulServiceContext stateful = context as StatefulServiceContext; + if (stateful != null) + { + return stateful.ReplicaId; + } + + throw new NotSupportedException("Context type not supported."); + } +#if UNSAFE + private int SizeInBytes(string s) + { + if (s == null) + { + return 0; + } + else + { + return (s.Length + 1) * sizeof(char); + } + } +#endif + #endregion + } +} diff --git a/samples/SfWeb/SfWeb.cs b/samples/SfWeb/SfWeb.cs new file mode 100644 index 0000000..898855a --- /dev/null +++ b/samples/SfWeb/SfWeb.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Fabric; +using System.IO; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ApplicationInsights.ServiceFabric; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.ServiceFabric.Services.Communication.AspNetCore; +using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using Serilog; + +namespace SfWeb +{ + internal sealed class SfWeb : StatelessService + { + public SfWeb(StatelessServiceContext context) + : base(context) + {} + + protected override IEnumerable CreateServiceInstanceListeners() + { + return new ServiceInstanceListener[] + { + new ServiceInstanceListener(serviceContext => + new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) => + { + ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}"); + + return new WebHostBuilder() + .UseKestrel() + .ConfigureServices( + services => services + .AddSingleton(serviceContext) + .AddSingleton(serviceProvider => + FabricTelemetryInitializerExtension.CreateFabricTelemetryInitializer(serviceContext))) + //NOTE https://github.com/microsoft/ApplicationInsights-ServiceFabric#net-core + //NOTE see startup + //NOTE : https://github.com/MicrosoftDocs/azure-docs/issues/27395#issuecomment-473767218 + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None) + .UseUrls(url) + .UseSerilog() //uses the static log, provides core ILogger - https://github.com/serilog/serilog-aspnetcore + .Build(); + })) + }; + } + } +} diff --git a/samples/SfWeb/SfWeb.csproj b/samples/SfWeb/SfWeb.csproj new file mode 100644 index 0000000..1bff77c --- /dev/null +++ b/samples/SfWeb/SfWeb.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.1 + True + True + win7-x64 + False + + + + + + + + + + + + + diff --git a/samples/SfWeb/Startup.cs b/samples/SfWeb/Startup.cs new file mode 100644 index 0000000..d25c8e1 --- /dev/null +++ b/samples/SfWeb/Startup.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Serilog; + +namespace SfWeb +{ + public class Startup + { + private readonly IConfiguration _configuration; + private readonly IWebHostEnvironment _env; + + public Startup(IConfiguration configuration, IWebHostEnvironment env) + { + _configuration = configuration; + _env = env; + } + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + //NOTE : https://github.com/MicrosoftDocs/azure-docs/issues/27395#issuecomment-473767218 + services.AddApplicationInsightsTelemetry(_configuration); + services.AddRouting(); + services.AddLogging(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => + { + var coreLoggerFactory = context.RequestServices.GetRequiredService(); + + Log.Logger.Information("Serilog Logger - Hello World"); + coreLoggerFactory.CreateLogger("Starup").LogInformation(".NET Core Logger - Hello World"); + await context.Response.WriteAsync("Hello World!"); + }); + }); + } + } +} diff --git a/samples/SfWeb/appsettings.Development.json b/samples/SfWeb/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/samples/SfWeb/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/samples/SfWeb/appsettings.json b/samples/SfWeb/appsettings.json new file mode 100644 index 0000000..d9d9a9b --- /dev/null +++ b/samples/SfWeb/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/SfWorker/PackageRoot/Config/Settings.xml b/samples/SfWorker/PackageRoot/Config/Settings.xml new file mode 100644 index 0000000..902c747 --- /dev/null +++ b/samples/SfWorker/PackageRoot/Config/Settings.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/samples/SfWorker/PackageRoot/ServiceManifest.xml b/samples/SfWorker/PackageRoot/ServiceManifest.xml new file mode 100644 index 0000000..8f0dea6 --- /dev/null +++ b/samples/SfWorker/PackageRoot/ServiceManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + SfWorker.exe + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SfWorker/Program.cs b/samples/SfWorker/Program.cs new file mode 100644 index 0000000..c26529c --- /dev/null +++ b/samples/SfWorker/Program.cs @@ -0,0 +1,50 @@ +using System; +using System.Diagnostics; +using System.Fabric; +using System.Threading; +using System.Threading.Tasks; +using CMP.ServiceFabric.Logging; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.ServiceFabric.Services.Runtime; +using Serilog; + +namespace SfWorker +{ + internal static class Program + { + private static void Main() + { + var serviceProvider = new ServiceCollection() + .AddApplicationInsightsTelemetryWorkerService("key") + .AddApplicationInsightsTelemetryProcessor() + .BuildServiceProvider(); + + var telemetryConfiguration = serviceProvider.GetRequiredService(); + + Log.Logger = new LoggerConfiguration() + .DefaultCmp(telemetryConfiguration, "development") + .CreateLogger(); + + try + { + ServiceRuntime.RegisterServiceAsync("SfWorkerType", + context => { + var coreLogger = context.ConfigureLogging(telemetryConfiguration, Log.Logger, "SfWorkerType"); + return new SfWorker(context, coreLogger); + } + + ).GetAwaiter().GetResult(); + + ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(SfWorker).Name); + + Thread.Sleep(Timeout.Infinite); + } + catch (Exception e) + { + ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); + throw; + } + } + } +} diff --git a/samples/SfWorker/ServiceEventSource.cs b/samples/SfWorker/ServiceEventSource.cs new file mode 100644 index 0000000..9e53141 --- /dev/null +++ b/samples/SfWorker/ServiceEventSource.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Fabric; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Runtime; + +namespace SfWorker +{ + [EventSource(Name = "MyCompany-Sample-SfWorker")] +internal sealed class ServiceEventSource : EventSource +{ + public static readonly ServiceEventSource Current = new ServiceEventSource(); + + // Instance constructor is private to enforce singleton semantics + private ServiceEventSource() : base() { } + + #region Keywords + // Event keywords can be used to categorize events. + // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). + // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. + public static class Keywords + { + public const EventKeywords Requests = (EventKeywords)0x1L; + public const EventKeywords ServiceInitialization = (EventKeywords)0x2L; + } + #endregion + + #region Events + // Define an instance method for each event you want to record and apply an [Event] attribute to it. + // The method name is the name of the event. + // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). + // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. + // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). + // Put [NonEvent] attribute on all methods that do not define an event. + // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx + + [NonEvent] + public void Message(string message, params object[] args) + { + if (this.IsEnabled()) + { + string finalMessage = string.Format(message, args); + Message(finalMessage); + } + } + + private const int MessageEventId = 1; + [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] + public void Message(string message) + { + if (this.IsEnabled()) + { + WriteEvent(MessageEventId, message); + } + } + + [NonEvent] + public void ServiceMessage(StatelessServiceContext serviceContext, string message, params object[] args) + { + if (this.IsEnabled()) + { + string finalMessage = string.Format(message, args); + ServiceMessage( + serviceContext.ServiceName.ToString(), + serviceContext.ServiceTypeName, + serviceContext.InstanceId, + serviceContext.PartitionId, + serviceContext.CodePackageActivationContext.ApplicationName, + serviceContext.CodePackageActivationContext.ApplicationTypeName, + serviceContext.NodeContext.NodeName, + finalMessage); + } + } + + // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. + // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. + // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. + private const int ServiceMessageEventId = 2; + [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] + private +#if UNSAFE + unsafe +#endif + void ServiceMessage( + string serviceName, + string serviceTypeName, + long replicaOrInstanceId, + Guid partitionId, + string applicationName, + string applicationTypeName, + string nodeName, + string message) + { +#if !UNSAFE + WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); +#else + const int numArgs = 8; + fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message) + { + EventData* eventData = stackalloc EventData[numArgs]; + eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) }; + eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) }; + eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) }; + eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) }; + eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) }; + eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) }; + eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) }; + eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) }; + + WriteEventCore(ServiceMessageEventId, numArgs, eventData); + } +#endif + } + + private const int ServiceTypeRegisteredEventId = 3; + [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] + public void ServiceTypeRegistered(int hostProcessId, string serviceType) + { + WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); + } + + private const int ServiceHostInitializationFailedEventId = 4; + [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] + public void ServiceHostInitializationFailed(string exception) + { + WriteEvent(ServiceHostInitializationFailedEventId, exception); + } + + // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. + // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, + // and other statistics. + private const int ServiceRequestStartEventId = 5; + [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] + public void ServiceRequestStart(string requestTypeName) + { + WriteEvent(ServiceRequestStartEventId, requestTypeName); + } + + private const int ServiceRequestStopEventId = 6; + [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] + public void ServiceRequestStop(string requestTypeName, string exception = "") + { + WriteEvent(ServiceRequestStopEventId, requestTypeName, exception); + } + #endregion + + #region Private methods +#if UNSAFE + private int SizeInBytes(string s) + { + if (s == null) + { + return 0; + } + else + { + return (s.Length + 1) * sizeof(char); + } + } +#endif + #endregion +} +} diff --git a/samples/SfWorker/SfWorker.cs b/samples/SfWorker/SfWorker.cs new file mode 100644 index 0000000..7db78be --- /dev/null +++ b/samples/SfWorker/SfWorker.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Fabric; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using Serilog; + +namespace SfWorker +{ + internal sealed class SfWorker : StatelessService + { + private readonly Microsoft.Extensions.Logging.ILogger logger; + + public SfWorker(StatelessServiceContext context, Microsoft.Extensions.Logging.ILogger logger) + : base(context) + { + this.logger = logger; + } + + protected override IEnumerable CreateServiceInstanceListeners() + { + return new ServiceInstanceListener[0]; + } + + protected override async Task RunAsync(CancellationToken cancellationToken) + { + long iterations = 0; + + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + ++iterations; + ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", iterations); + Log.Logger.Information("Serilog Logger Working-{0}", iterations); + this.logger.LogInformation(".NET Core Logger Working-{0}", iterations); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } + } + } +} diff --git a/samples/SfWorker/SfWorker.csproj b/samples/SfWorker/SfWorker.csproj new file mode 100644 index 0000000..0f09c8c --- /dev/null +++ b/samples/SfWorker/SfWorker.csproj @@ -0,0 +1,21 @@ + + + + Exe + netcoreapp3.1 + True + True + win7-x64 + False + + + + + + + + + + + +