Serilog Cloudwatch logging not enriching the logs - .net-core

I have used Serilog in the past and enriched logs with various properties. However I am playing around with the new AWS Lambda Serverless templates using .net core 3.1 and cannot get the logs to enrich. I have tried this in a basic Console app as well with the same result.
Example: code:
class Program
{
static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.AWSSeriLog(GetAwsSerilogConfiguration())
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.CreateLogger();
using (LogContext.PushProperty("A", 1))
{
Log.Information("Starting web host");
Console.WriteLine("Hello World!");
}
}
private static AWSLoggerConfig GetAwsSerilogConfiguration()
{
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
return new AWSLoggerConfig
{
LogGroup = $"AwsLoggingTestConsoleApp/{environmentName ?? "Development"}",
Region = RegionEndpoint.APSoutheast2.SystemName
};
}
}
The following screenshots from Cloudwatch Logs and Insights show the log generated by this code. The enriched property 'A' and MachineName do not appear
Cloudwatch Logs
Cloudwatch Insights
I feel like I am missing something obvious, but for the life of me I cannot see it.
Any ideas why the logs are not being enriched?
Many thanks,
M.

Related

Routing WebView2 REST calls to local .NET 5 Controllers

I'm currently designing an Angular SPA web client, backed with .NET5 REST. It's all in the same Visual Studio project, and it builds / runs fine.
I'm now investigating the possibility of distributing this as a windows desktop application. I was able to get Electron.NET to work, but it seems like a round-about solution (Node?!). I also didn't particularly like that the resources were visible/changeable in the distributed app.
This led me to investigate using WebView2 within WPF (Microsoft seems to be making a similar transition with MSTeams.) I've found some examples, but they only use:
solely remote content ("www.bing.com")
local content, but only img / html / etc
postmessage, etc to communicate using custom objects.
None of these is what I want. Well, that's not entirely true. I need #2 to load the Angular SPA, but when the WebView2-hosted Angular invokes HttpClient, I'd like to intercept that request in the host application and Route it to my REST Controllers. This would allow me to keep nearly all of my code intact, and presumably ship a smaller, more obfuscated exe.
Is this possible? obvious? Is my desire fundamentally flawed? (wouldn't be the first time)
Chromium.AspNetCore.Bridge offers a solution to the problem. It uses owin to host the server-side code in memory, and provides a RequestInterceptor to cleanly relay all requests to the "server" code.
The link above has working examples, but briefly:
App.xaml.cs:
private IWebHost _host;
private AppFunc _appFunc;
public AppFunc AppFunc
{
get { return _appFunc; }
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
_ = Task.Run(async () =>
{
var builder = new WebHostBuilder();
builder.ConfigureServices(services =>
{
var server = new OwinServer();
server.UseOwin(appFunc =>
{
_appFunc = appFunc;
});
services.AddSingleton<IServer>(server);
});
_host = builder
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.Build();
await _host.RunAsync();
});
}
MainWindow.xaml.cs
private AppFunc _appFunc;
public MainWindow()
{
InitializeComponent();
Browser.CoreWebView2InitializationCompleted += Browser_CoreWebView2InitializationCompleted;
}
private void Browser_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
if (e.IsSuccess)
{
_appFunc = ((App)Application.Current).AppFunc;
Browser.CoreWebView2.WebResourceRequested += BrowserWebResourceRequestedAsync;
Browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
}
}
private async void BrowserWebResourceRequestedAsync(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
var deferral = e.GetDeferral();
var request = new ResourceRequest(e.Request.Uri, e.Request.Method, e.Request.Headers, e.Request.Content);
var response = await RequestInterceptor.ProcessRequest(_appFunc, request);
var coreWebView2 = (CoreWebView2)sender;
e.Response = coreWebView2.Environment.CreateWebResourceResponse(response.Stream, response.StatusCode, response.ReasonPhrase, response.GetHeaderString());
deferral.Complete();
}

dotnet core TopShelf Windows Service fails to start

I have a dotnet core console application build to connect to a Sql Service Broker instance to monitor table changes.
The app monitors one table that is updated from an ERP system and then publishes messages to our bus.
It runs fine when running as a console application, or debugging in my IDE.
I am having an issue when using TopShelf to configure it as a windows service.
Here is the entry point:
private static void Main(string[] args)
{
RegisterComponents();
var serviceHost = HostFactory.Run(sc =>
{
sc.Service<ISalesOrderMonitorService>(s =>
{
var sqlListener = _container.ResolveNamed<SqlDependencyEx>(ListenerKey.SalesOrder);
var changeHandler = _container.Resolve<ISalesOrderChangeHandler>();
var listenerConfig = _container.ResolveNamed<ListenerConfiguration>(ListenerKey.SalesOrder);
var logger = _container.Resolve<ILogger<SalesOrder>>();
s.ConstructUsing(f =>
new SalesOrderMonitorService(sqlListener, changeHandler, listenerConfig, logger));
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
});
var exitCode = (int) Convert.ChangeType(serviceHost, serviceHost.GetType());
Environment.ExitCode = exitCode;
}
The "worker" class:
public abstract class ServiceBase<T, TZ> : IService<T>
where T : IChangeHandler
{
protected readonly IChangeHandler ChangeHandler;
protected readonly SqlDependencyEx Listener;
protected readonly ListenerConfiguration ListenerConfiguration;
protected readonly ILogger<TZ> Logger;
protected ServiceBase(SqlDependencyEx listener, IChangeHandler changeHandler,
ListenerConfiguration listenerConfiguration, ILogger<TZ> logger)
{
Logger = logger;
ListenerConfiguration = listenerConfiguration;
Listener = listener;
ChangeHandler = changeHandler;
}
public virtual void Start()
{
try
{
Listener.TableChanged += (o, e) => ChangeHandler.Process(e);
Listener.Start();
Logger.LogDebug(
$"Listening to changes on the {ListenerConfiguration.Table} table in the {ListenerConfiguration.Database} database");
}
catch (Exception e)
{
Logger.LogError(e, e.Message);
throw;
}
}
public virtual void Stop()
{
Listener.Stop();
}
Install through TopShelf is no problem:
c:>{ServiceName}.exe install -username "serviceAccount" -password "superSecret" -servicename "ServiceName" -servicedescription "Description" -displayname "Service DisplayName" --autostart
When I go to start the service - I get this:
This is misleading because the event viewer shows this:
This is happening way faster than 30 seconds. This is definitely related to how I am configuring TopShelf.
As stated - the application works just fine when run "debug" or even as just an exe console.
I got it figured out. Actually both comments from #DotNetPadawan and #Lex Li indirectly got me there.
For starters - enabling the remote debugger clued me in that my appsetting.json was not being read into my IConfiguration. That was really confusing because everything works fine running locally with a debugger or even just starting the exe.
The link Lex Li points out did not provide the answer - however that article had this reference:
Host and Deploy aspnetcore as a Windows Service
It was here that I found this little nugget:
The current working directory returned by calling GetCurrentDirectory for a Windows Service is the C:\WINDOWS\system32 folder. The system32 folder isn't a suitable location to store a service's files (for example, settings files). Use one of the following approaches to maintain and access a service's assets and settings files.
The link explains how to conditionally set the current directory if the app is running as a service.
var isConsole = args.Contains("-mode:console");
if (!isConsole)
{
var pathToExe = Process.GetCurrentProcess().MainModule?.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
Putting this out there for anyone else that runs into this problem.
Admittedly - netcore 3.0 is likely the better way to go - but I don't have the bandwidth to upgrade everything is this repo (lots of shared stuff) to 3.0. I needed to get this working.

Application Insights for .NET Core Azure WebJob

When I try to setup my .NET Core WebJob to use Application Insights, I get the following Exception on startup:
System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.AspNetCore.Hosting.IHostingEnvironment' while attempting to activate 'Microsoft.AspNetCore.Hosting.DefaultApplicationInsightsServiceConfigureOptions'.'
I'm sure I'm overlooking something, but I can't find it out. My Main method is like in many examples, like here
public static void Main(string[] args)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
Configuration.EnvironmentName = environment;
Configuration.IsDevelopment = string.Equals(environment, "Development");
var host = new HostBuilder()
.UseEnvironment("Development")
.ConfigureWebJobs(b =>
{
b.UseHostId("ecad61-62cf-47f4-93b4-6efcded6")
.AddAzureStorageCoreServices()
.AddAzureStorage()
.AddTimers()
.AddEventHubs();
})
.ConfigureServices(x => ConfigureServices(x))
.ConfigureAppConfiguration(b =>
{
b.AddJsonFile("appsettings.json", false, false);
b.AddJsonFile($"appsettings.{environment}.json", true);
b.AddEnvironmentVariables();
Configuration.Config = b.Build();
})
.ConfigureLogging((context, b) =>
{
b.AddConfiguration(Configuration.Config);
b.SetMinimumLevel(LogLevel.Trace);
b.AddConsole();
b.AddDebug();
//TODO fix applicationInsights
string appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
if (!string.IsNullOrEmpty(appInsightsKey))
{
b.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
}
})
.Build();
using (host)
{
host.Run();
}
}
At first glance (and true shot in the dark), I would check to see if context.Configuration this throwing the exception because APPINSIGHTS_INSTRUMENTATIONKEY doesn't exist in the collection. The missing key could be throwing an exception that's bubbling up to your DI container.
EDIT: Trying giving this package a try and let me know if works. It's currently in pre-release. https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights/
EDIT: The call to AddApplicationInsightsTelemetry uses DefaultApplicationInsightsServiceConfigureOptions is dependent on IHostingEnvironment. IHostingEnvironment isn't used by the WebJobsSDK which is causing your exception. The WebJobsSDK has it's on usage of Application Insights and you should be able to use it similarily to https://github.com/Azure/azure-webjobs-sdk/tree/dev/sample/SampleHost sample

How to setup PUB/SUB NetMQ in Xamarin Forms

I have a Windows Services running as a Publisher and I am trying to setup Xamarin Forms as the Subscriber. The code below works just fine in a Console App or LinqPad, but when copied and pasted into Xamarin Forms, the SubscriberSocket just does not respond to messages from the server.
Do you know how to wire this up?
I am using NetMQ v 4.0.0.1
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
Task.Run(() => StartPubSubSocketSubscriber());
}
private void StartPubSubSocketSubscriber()
{
string topic = "TopicA";
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.30.120:5556");
subSocket.Subscribe(topic);
while (true)
{
string messageTopicReceived = subSocket.ReceiveFrameString();
string messageReceived = subSocket.ReceiveFrameString();
Device.BeginInvokeOnMainThread(() =>
{
label.Text = messageReceived;
});
}
}
}
}
I also tried starting the background thread with Task.Factory.StartNew(() => StartPubSubSocketSubscriber(), TaskCreationOptions.LongRunning); but it is just as unresponsive to messages from the publisher.
Thank you.
PS.: removed subSocket.Connect("tcp://localhost:5556");
The fix for this was a 2 step process:
The SubscriberSocket was incorrectly pointing to localhost. An understandable mistake since the emulator runs on the same machine as the server application. Make sure the Subscriber has the explicit IP address when running on a virtual environment or another device.
The issue with SubscriberSocket not responding was actually on a server. I had set it up with pubSocket.Bind("tcp://localhost:5556");, once I changed it to pubSocket.Bind("tcp://*:5556"); the SubscriberSocket started responding. This is an error in documentation.
The hint to the solution came from the NetMQ github issue tracking:
https://github.com/zeromq/netmq/issues/747

ITelemetryProcessor behavior when deployed to AppService

I have created a custom telemetry processor which is adding customer properties to the telemetry items. When running locally, I don’t see any issue and I am seeing the properties being added(both in release and debug mode) and logged to the AppInsights.
When deployed to app service, I am seeing the logs, but the properties being added by the telemetry processor are missing.
I am using .Net Core 2.1 and the Application insights NuGet version is 2.3.0. Is there a way to debug why this is happening? Also is anyone aware if this is a known issue?
Can you share your code which adds application insights and the telemetry processor? It should be something like this:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddApplicationInsightsTelemetry();
services.AddApplicationInsightsTelemetryProcessor<MyFirstCustomTelemetryProcessor>();
// If you have more processors:
services.AddApplicationInsightsTelemetryProcessor<MySecondCustomTelemetryProcessor>();
// ...
}
Can you try to print the list of TelemetryProcessors registered with the TelemetryConfiguration instance? You can constructor inject TelemetryConfiguration to a controller class, and print out the list. Something like shown below.
string tpList;
public ValuesController(TelemetryConfiguration tc)
{
var tps = tc.TelemetryProcessors;
foreach(var tp in tps)
{
var s = tp.GetType().ToString();
tpList += s;
}
}
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2", tpList };
}
This should confirm if the TelemetryProcessor is even in the config.
Also, when you say works local - do you mean when running from Visual Studio? VS alters behavior, so can try to run locally outside of VS, and see if it reproes.

Resources