How to set Telemetry Channel for Application Insights Log4Net Appender? - c#

I added those Nuget Packages to my WPF App:
Microsoft.ApplicationInsights.Log4NetAppender
Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel
The logger is logging in a file, that works. But no data is transferred to Azure.
I got this error:
AI: Server telemetry channel was not initialized. So persistent storage is turned off. You need to call ServerTelemetryChannel.Initialize(). Currently monitoring will continue but if telemetry cannot be sent it will be dropped.
My Question: Where (in the code) should i initialize the telemetry channel? And why do i have to do this? What's the appender for if i have to add a telemetry client (with config) anyways?

Update 0603:
my app.config:
Debug with visual studio:
Update: please follow the screenshot below, and try to find the info you send. And if you still cannot find the info, please provide you detailed code(remove the personal/important data like instrumentation key, and also provide us the nuget package and version you're using).
1.click the search button in overview page:
2.in the search screen, make the Local time and Event types are set correctly, then try to search the message:
You'd better provide the code to set log4net and app insights key.
I did a simple test with wpf project, the below code works fine:
public partial class MainWindow : Window
{
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
log.Info("wpf aaaa11111");
InitializeComponent();
}
}
You get the error "AI: Server telemetry channel was not initialized", maybe due to some incorrect configuration, like use the following code in the above working code:
//when add the code, it will cause the error you mentioned.
TelemetryConfiguration.Active.TelemetryChannel = new ServerTelemetryChannel();
If you have to add a telemetry client (with config), and with proper configuration, both log4net and telemetry client can send data to application insights. The code like below:
public partial class MainWindow : Window
{
private readonly TelemetryClient telemetryClient;
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
//configure the key here for log4net
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
var config = new TelemetryConfiguration();
//configure the key here for telemetry client
config.InstrumentationKey = "the key";
telemetryClient = new TelemetryClient(config);
log.Info("wpf aaaa333");
log.Info(TelemetryConfiguration.Active.TelemetryChannel.ToString());
telemetryClient.TrackTrace("it is going to start!");
InitializeComponent();
}
}

So, finally everything works. I offer the required steps here again:
Add NugetPackages:
log4net, Microsoft.ApplicationInsights, Microsoft.ApplicationInsights.Log4NetAppender and Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel to the Project
In MainWindow.xaml.cs:
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
log.Info("wpf aaaa11111");
InitializeComponent();
}
}
In App.config:
Done
Big thanks to #Ivan Yang for his solution and his time helping me!

Related

How to properly set up Azure Functions logging, live metrics, and app insights with dependency injection

About a month ago, I noticed that some of the monitoring functionality in the old Azure Functions portal interface stopped working. I wrote more details about the issues on the Azure Functions Host GitHub but my particular questions are as of yet unanswered.
Now it seems the Azure Functions portal interface default to the new "management experience" that looks more similar to the rest of Azure, and with that, it's even more apparent that something is wrong in the way we use logging and tracing.
My question is: Does anybody have any code samples as to how to set up Azure Function logging, live metrics, and app insights tracing so that it:
Works with dependency injection
Works with the new "management experience" interface
Currently, in order to see what a particular Azure Function is doing, I have to go to the old Azure interface and study the log stream. The Functions do work, and they spit out information in the log stream, but only in the old interface, and not much else in terms of monitoring seems to work. Using the old interface:
The invocation logs, the one you get when you press the "Monitor" link under "Functions(Read Only) > [function] > Monitor, shows no invocations at all even though the functions are definitely being called according to the logs.
The Live app metrics link results in the default "Not available: your app is offline or using an older SDK" with some animated demo charts.
These worked fine a month ago. Now, not so much.
Using the new interface:
Monitoring > Log stream shows nothing except the word "Connected!", regardless of verbosity.
Monitoring > Log Stream > Open in Live Metrics again just yields the default "Not available: your app is offline or using an older SDK".
Going to a specific function in the new interface by using Functions > Functions > [click on a function]:
Developer > Code + Test > Test-button > Run, the Logs window pops up, just says "Connected!" and nothing else, again regardless of verbosity.
Monitor > Invocations, there are no invocation traces registered here, even though the function is obviously being called according to the old interface log stream.
Monitor > Logs, again, just says "Connected!", regardless of verbosity.
I don't understand why it suddenly stopped working a month back, and why so many things don't seem to work with the new interface. Our Functions' NuGet packages are all up to date.
In terms of logging, the logger is dependency injected so that we can use it in multiple classes and not just in the default Functions.cs class:
using Microsoft.Extensions.Logging;
public class EventForwarder
{
private readonly ILogger<EventForwarder> log;
And we log through the use of extension methods, nothing fancy really:
using Microsoft.Extensions.Logging;
public static class LoggerExtensions
{
public static void Info(this ILogger log, string msg) => log.LogInformation(msg);
The app insights tracer is also dependency injected using a workaround suggested here, i.e. our Startup.cs looks lite this:
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(EventForwarder.Startup))]
namespace EventForwarder
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// https://github.com/Azure/azure-functions-host/issues/5353
builder.Services.AddSingleton(sp =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
return string.IsNullOrWhiteSpace(key) ? new TelemetryConfiguration() : new TelemetryConfiguration(key);
});
We're performing traces of Http retries, among other things, like so:
public class HttpRetryPolicyService
{
private readonly ILogger<HttpRetryPolicyService> log;
private readonly TelemetryClient insights;
public HttpRetryPolicyService(ILogger<HttpRetryPolicyService> log,
TelemetryConfiguration insightsConfig)
{
this.log = log;
insights = new TelemetryClient(insightsConfig);
}
...
private void LogRetry(DelegateResult<HttpResponseMessage> message, TimeSpan delay, int attempt, Context context)
{
if (message.Exception != null)
{
log.Warn($"Exception details: {message.Exception}");
insights.Track(message.Exception);
And we're using extension methods to trace, like so:
using Microsoft.ApplicationInsights;
namespace EventForwarder.Static
{
public static class TelemetryExtensions
{
public static void Track(this TelemetryClient insights, string eventName)
{
insights.TrackEvent(eventName);
insights.Flush();
}
What am I missing?
Edit #1: Btw, adding Application Insights as a Service Dependency in the Publish dialog unfortunately does not solve these issues.
Edit #2: Also, preemtively, our Functions host.json files all look like this:
{
"version": "2.0",
"healthMonitor": {
"enabled": true,
"healthCheckInterval": "00:00:10",
"healthCheckWindow": "00:02:00",
"healthCheckThreshold": 6,
"counterThreshold": 0.80
},
"logging": {
"fileLoggingMode": "always",
"applicationInsights": {
"enableLiveMetrics": true,
"samplingSettings": {
"isEnabled": true
}
},
"logLevel": {
"EventForwarder": "Information"
}
}
}
This is what breaks your app, remove it and everything should work:
// https://github.com/Azure/azure-functions-host/issues/5353
builder.Services.AddSingleton(sp =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
return string.IsNullOrWhiteSpace(key) ? new TelemetryConfiguration() : new TelemetryConfiguration(key);
});
My guess would be that the workaround actually breaks the logging now that the bugfix has been rolled out.
I created a sample app where logging and log stream work quite nicely, also with dependency injection. I tested it with both Windows and Linux consumption plans. The function app was created using the wizard in the Azure Portal, selecting .NET Core 3.1. Please be aware that TrackEvent does not show up in the function's log stream. It shows up in Application Insights Live Metrics. It can also take up to 30s after "Connected" shows up until actual logs are shown. The Live Metrics view works better, especially if you open directly from application insights.
I was able to reproduce your issues by applying the "workaround" mentioned above. Without it, everything works fine.
Full sample: https://github.com/LXBdev/Functions-V3-sample
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<MyService>();
}
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
},
"logLevel": {
"Functions_V3_sample": "Information"
}
}
public MyService(ILogger<MyService> logger, TelemetryClient telemetry)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
Telemetry = telemetry ?? throw new ArgumentNullException(nameof(telemetry));
}
public void Foo()
{
Logger.LogInformation("Foo");
Telemetry.TrackTrace("BarLog", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information);
Telemetry.TrackEvent("BarEvent");
}
Update: There was an issue with the host.json in my original answer and sample - logs weren't really persisted to AppInsights because of https://github.com/Azure/azure-functions-host/issues/4345. I updated the code accordingly.

Why is Application Insights TrackException not logging anything?

I'm currently trying to log exceptions in Application Insights for later investigation.
However, any exception I try to log with the TrackException method does not appear in Application Insights.
The docs for Application Insights event filtering state the following:
Exception - Uncaught exceptions in the server, and those that you log by using TrackException().
I'm using the following code to log my exception:
private static readonly TelemetryClient Client = new TelemetryClient{InstrumentationKey = ApplicationInsightsSettings.InstrumentationKey};
public static void TrackException(Exception exception, string traceReference)
{
var properties = new Dictionary<string, string> {{"Trace Reference", traceReference}};
Client.TrackException(exception);
Client.TrackException(exception, properties);
Client.TrackEvent(traceReference);
}
Whenever I run this code only an event is logged but none of the exceptions are.

Application insight log exceptions only

I want to use Application Insights to log exceptions only. How can I do that?
I tried searching for ways turning other settings off such as this and it says that there is no way to turn it off.
I tried ITelemetryProcessor and encountered the same problem as this question. I tried both config and code ways of registering ITelemetryProcessor but it is not hit even if I explicitly throw an exception in my Web API controller.
I am using VS 2017 and created a new .Net Framework 4.6.2 Web API. I also have an InstrumentationKey and can see the exception logged in Azure portal.
First of all, the first link you referenced is nothing to do with your issue.
You want to only log the exceptions, but that link means that remove the old telemetry data like Trace in repository(where the telemetry data is stored after upload to app insights).
You can take use of ITelemetryProcessor to log exceptions only. Please follow my steps as below:
1.Add Application insights to your web api project by right clicking your project name -> select Configure Application Insights:
After SDK added, do not select the Enable trace collection:
2.Add a .cs file in your project, then implement your custom ITelemetryProcessor class, code is as below:
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
namespace WebApplicationWebApi
{
public class ExceptionsFilter:ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
public ExceptionsFilter(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry item)
{
string s = item.GetType().Name;
//if it's not exception telemetry, just return without log it to app insights.
if (s != "ExceptionTelemetry")
{
return;
}
this.Next.Process(item);
}
}
}
3.Register your custom ITelemetryProcessor in the ApplicationInsights.config. In the node, add <Add Type="WebApplicationWebApi.ExceptionsFilter,WebApplicationWebApi"/> :
4.Then run your code. To make sure the custom ITelemetryProcessor class is called, you can set a breakpoint in that class to see if it's hit when running.
And for the testing purpose, I add some telemetry data in the HomeController.cs:
public class HomeController : Controller
{
TelemetryClient client = new TelemetryClient();
public ActionResult Index()
{
RequestTelemetry r1 = new RequestTelemetry();
r1.Name = "request message for testing";
client.TrackRequest(r1);
client.TrackTrace("trace message for testing wwwww.");
client.TrackException(new Exception("exception message for testing wwwww."));
ViewBag.Title = "Home Page";
return View();
}
}
5.In your visual studio output window, you should see these messages:
6.Then in visual studio, nav to Application Insights Search (in vs -> view -> other windows -> Application Insights Search), then check if there are some values here(if it has values like "4" in screenshot below, click on it):
7.If it has values in step 6, please click the update button, then check All:
8.Then you can see that only the Exceptions are logged:

Global exception handling in ASP.NET Web API 2.1 with NLog?

ASP.NET Web API 2.1 includes a new global error handling capability. I found an example that demonstrates how to log exceptions into ELMAH. But I use NLog to log errors to a database table. Is it possible to use Web API global error handling with NLog? If so, please provide an example.
It's actually quite simple, you either implement IExceptionLogger by hand or inherit from the base class, ExceptionLogger.
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
Nlog.LogException(LogLevel.Error, RequestToString(context.Request), context.Exception);
}
private static string RequestToString(HttpRequestMessage request)
{
var message = new StringBuilder();
if (request.Method != null)
message.Append(request.Method);
if (request.RequestUri != null)
message.Append(" ").Append(request.RequestUri);
return message.ToString();
}
}
Also add it to the config:
var config = new HttpConfiguration();
config.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
You can find full sample solution here.
Other thing that might be handy WebApiContrib.Tracing.NLog package that allows you to use ITraceWriter interface to output to logs with NLog. A cool thing about ITraceWriter is that "all traces can correlate to the single request that caused that code to run (see this link)

log4net custom properties not working with multi-threaded app

I have an app that is using the log4net AdoNetAppender (DB appender) to write my logs to the database. It is writing the records to the DB, but the custom fields are all NULL. They work fine using the same code in my unit tests, but not when they are called when the application is running. It is a multi-threaded application that processes messages off of a message queue.
Is there any known issues (that anyone is aware of) regarding custom properties for the DB appender with multi-threaded applications? That is my only guess as to why they are not working when the app is spun up because I can't reproduce in unit tests, etc.
The default log4net fields come through fine.
I am setting the custom property values in a Singleton:
public sealed class Logger
{
private static readonly Logger instance = new Logger();
public static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Static constructor which sets the properties for the database logging using log4net. This enables analysts to view the log events
/// inside the database as well as in the local application log file.
/// </summary>
static Logger()
{
GlobalContext.Properties["Application"] = "MyApp";
GlobalContext.Properties["ApplicationVersion"] = Utility.GetApplicationVersion();
var windowsHost = System.Net.Dns.GetHostName();
if (!String.IsNullOrEmpty(windowsHost))
LogicalThreadContext.Properties["Host"] = windowsHost;
//ThreadContext.Properties["LogTime"] = DateTime.Now;
var windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
if (windowsIdentity != null)
GlobalContext.Properties["CreatedBy"] = windowsIdentity.Name;
}
private Logger()
{
}
public static Logger Instance
{
get { return instance; }
}
}
EDIT:
Found this going to try and add additional log4net debugging.
http://logging.apache.org/log4net/release/faq.html#internalDebug
Not seeing any errors in log4nets internal logs so still unclear about what is going on.
I finally figured it out. It was how we were trying to set the custom properties globally. I instead set the properties on app startup prior to any of my instances binding to the queue and processing messages. That seemed to do it....not sure why I didn't think of that in the beginning. Just used the log4net GlobalContext and worked like a charm.
--S

Categories