How to set Cloud_RoleName in Service Fabric - azure

I'm trying to get a more user-friendly component name in Application Insights Application Map. I found examples but not for Service Fabric specifically.
How do you integrate that with the FabricTelemetryInitializer that is part of the Kestrel WebHostBuilder?

If you are not using the Application Insights Service Fabric nuget package, then you should use it to set your cloud role.
https://www.nuget.org/packages/Microsoft.ApplicationInsights.ServiceFabric
https://www.nuget.org/packages/Microsoft.ApplicationInsights.ServiceFabric.Native
Microsoft.ApplicationInsights.ServiceFabric.Native should be used if your application has references to service fabric runtime since this library is relevant to concepts like ServiceContext, Service Remoting, etc. Microsoft.ApplicationInsights.ServiceFabric should be used if your application runs in service fabric but has no reference to service fabric runtime.
Since you mentioned FabricTelemetryInitializer, I assume you are using these nuget packages already. You can see how FabricyTelemetryInitializer can be hooked up here:
https://github.com/microsoft/applicationinsights-servicefabric#net-core-1
If you don't have a service context object, then don't pass in one to the constructor and FabricTelemetryInitializer will just rely on environment variables.
See here for the actual logic:
https://github.com/Microsoft/ApplicationInsights-ServiceFabric/blob/master/src/ApplicationInsights.ServiceFabric/Shared/FabricTelemetryInitializer.cs#L81

I think you can use this code:
[DebuggerStepThrough]
public class ServiceNameInitializer : ITelemetryInitializer
{
/// <inheritdoc />
public void Initialize(ITelemetry telemetry)
{
telemetry.Context.Cloud.RoleName = "ServiceA";
}
}
And in ConfigureServices add:
services.AddSingleton<ITelemetryInitializer, ServiceNameInitializer>();

Related

How to get instance name of Azure App Service in .Net Core

I need to get the name or id of the instance that my code is running on at runtime. For example:
MyApp_0 or MyApp_1
How can I do this in .Net Core when it is deployed to an app service?
You can use the REST API's method Web Apps - Get Instance Process And under the environment_variables you would see COMPUTERNAME
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/instances/{instanceId}/processes/{processId}?api-version=2019-08-01
Try use Environment.MachineName, if that does not work then use Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider.GetHostIdAsync.
The IHostIdProvider should be registered by default according the to the docs, so all you need to do is to inject it and use it.
public interface IHostIdProvider
{
Task<string> GetHostIdAsync(CancellationToken cancellationToken);
}

How to use different Connection strings for Azure SignalR Service in Function Apps?

Alright, so we have multiple signalR services and what we want to do is when our code is deployed, we want the connection string to be picked from our custom configuration file instead of the function App settings.
This is the negotiate function. See the "SignalRConnectionInfo" attribute.
[FunctionName("negotiate")]
public IActionResult negotiate(
[HttpTrigger(AuthorizationLevel.Function, "post")]
HttpRequest req,
[SignalRConnectionInfo(HubName = HubName, ConnectionStringSetting = **"Cannot pass dynamic connection string here as it requies a constant"**)]
SignalRConnectionInfo connectionInfo )
{
}
we tried adding it in Startup.cs
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
IConfigurationRoot config;
builder.Services.AddSignalR().AddAzureSignalR(config["SignalrConnectionString"]);
}
}
and it does not work this way. as it gives an error
Invalid host services. Microsoft.Azure.WebJobs.Script.WebHost: The following service registrations did not match the expected services:
[Invalid] ServiceType: Microsoft.Extensions.Hosting.IHostedService, Lifetime: Singleton, ImplementationType: Microsoft.Azure.SignalR.HeartBeat
Value cannot be null.
Parameter name: provider
So, is there any other way to use it in the function?
If you want to pick connection strings from custom configuration files, you should first add the configuration files as configuration sources.
See
https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources
The SignalR Function extension would pick the connection from a fixed location, by default AzureSignalRConnectionString, and you can customize it via ConnectionStringSetting.
If you have multiple SignalR service instances, you might want to use multiple endpoints support. Currently only Persistent service transport type supports multiple SignalR instances, that is, function would establish WebSocket connections with all the SignalR instances and you could customize the routing logic. This behaviour is different to picking one instance at the function startup. See https://github.com/Azure/azure-functions-signalrservice-extension/blob/dev/docs/sharding.md .
If you don't want to connect to all the SignalR instances, you can configure each connection string in one file, and pick one file as the configuration source that would be added at function startup.

Application insights not generated for .Net core app deployed on service fabric Linux cluster

I have a .Net core application that is deployed on service fabric Linux cluster. Application insights are configured in the app.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions aiOptions
= new ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions
{
EnableAdaptiveSampling = false,
EnableQuickPulseMetricStream = false,
InstrumentationKey = "xxx"
};
services.AddApplicationInsightsTelemetry(aiOptions);
I have a controller class that has some action methods and logs the information.
[HttpPost]
public ActionResult actionMethod(...)
{
TraceLine("------------------------------------");
//some code
}
private static void TraceLine(string msg)
{
msg = $">> {DateTime.UtcNow.ToString("o")}: {msg}";
Log.Information(msg);
}
I am using Serilog, configured in appsettings.json & Program.cs
When I hit action method directly from local (without hosting it on even local sf cluster), via Postman, I see app insights getting generated and pushed to azure.
azure app insights snapshot
But when I hit the action method that is deployed on Azure service fabric I don't see any insight getting generated.
What am I missing here?
Any help is much appreciated!
Well, we need to check a few things here:
1) The app insights URL and the instrumentation key in the deployment parameter files for cluster hosted on cloud (Cloud.xml)
2) After checking the Cloud.xml, the best way is to access the log files and check what is the actual problem.
There's a description here which explains how to discover where the log files are stored.
You can use RDP to access the machine, which is explained here.
I was able to solve the issue by using Microsoft.ApplicationInsights.ServiceFabric.Native SDK in my application to log app insights.
Refer .NetCore section in ApplicationInsights-ServiceFabric on how to configure insights for service fabric application.

How to Get Service Fabric Project Settings.xml Values

I have 5 service fabric stateless services. I have to get these service fabric settings.xml values in a class library based on Section Name of each file. I am going to create a common class which will take SectionName as a parameter and have to get all configuration values.
you can use this as a starting point:
internal sealed class YourService: StatelessService
{
public YourService(StatelessServiceContext context)
: base(context)
{
var configurationPackage = Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
var sectionParams = configurationPackage.Settings.Sections["sectionname"].Parameters;
// You can now iterate through these parameters (e.g. get count and access by index)
//sectionParams.Count;
//sectionParams[0].Name;
//sectionParams[0].Value;
I am not sure if there is a way for a library to find the ServiceContext of other Services. Please also be aware that not all services might be deployed to the same nodes. This might affect configuration availability.
You might need to create a central service or actor that collects the configuration values of all other services.

How To migrate windows service in Azure service fabric

I want to migrate typical windows service which is written in .net to Azure using Service fabric.
To implement this , I am creating one service fabric application containing one micro service as guest executable which uses .exe of windows service and deploying application package to service fabric cluster.
After deploying service fabric application on cluster I want windows service should install & start automatically on all nodes however at any time application is running on any single node. I want windows service should run on only one node at a time.
Please kindly help to implement this.
You can certainly run your service as a guest executable. Making sure it only runs on one node can be done by setting the instance count to 1 in the manifest, like so:
<Parameters>
<Parameter Name="GuestService_InstanceCount" DefaultValue="-1" />
</Parameters>
...
<DefaultServices>
<Service Name="GuestService">
<StatelessService ServiceTypeName="GuestServiceType"
InstanceCount="[GuestService_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
Or, you could actually migrate it, not just re-host it in the SF environment...
If your Windows Service is written in .NET and the you wan't to benefit from Service Fabric then the job of migrating the code from a Windows Service to a Reliable Service in Service Fabric should not be to big.
Example for a basic service:
If you start by creating a Stateless Service in a Service Fabric application you end up with a service implementation that looks like (comments removed):
internal sealed class MigratedService : StatelessService
{
public MigratedService(StatelessServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[0];
}
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// TODO: Replace the following sample code with your own logic
// or remove this RunAsync override if it's not needed in your service.
long iterations = 0;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
The RunAsync method starts running as soon as the Service is up and running on a node in the cluster. It will continue to run until the cluster, for some reason, decides to stop the service, or move it to another node.
In your Windows Service code you should have a method that is run on start. This is usually where you set up a Timer or similar to start doing something on a continuous basis:
protected override void OnStart(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 60000; // 60 seconds
timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
timer.Start();
}
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
...
DoServiceStuff();
Console.WriteLine("Windows Service says hello");
}
Now grab that code in OnTimer and put it in your RunAsync method (and any other code you need):
protected override async Task RunAsync(CancellationToken cancellationToken)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
DoServiceStuff();
ServiceEventSource.Current.ServiceMessage(this.Context,
"Reliable Service says hello");
await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
}
}
Note the Task.Delay(...), it should be set to the same interval as your Windows Service had for it's Timer.
Now, if you have logging in your Windows Service and you use ETW, then that should work out of the box for you. You simply need to set up some way of looking at those logs from Azure now, for instance using Log Analytics (https://learn.microsoft.com/en-us/azure/log-analytics/log-analytics-service-fabric).
Other things you might have to migrate is if you run specific code on shut down, on continue, and if you have any parameters sent to the service on startup (for instance connection strings to databases). Those need to be converted to configuration settings for the service, look at SO 33928204 for a starting point for that.
The idea behind service fabric is so that it manages your services, from deployment and running. Once you've deployed your service/application to the service fabric instance it will be just like running a windows service (kinda) so you wont need to install your windows service. If you're using something like TopShelf you can just run the exe and everything will run totally fine within service fabric.

Resources