Programmatically setting Application Insights instrumentation key throws error - c#

To support Application Insights in multiple environments, we are setting the Instrumentation Key programmatically, as adviced in this post.
We have left <InstrumentationKey> in ApplicationInsights.config empty, and instead added an application setting in web.config:
<add key="ApplicationInsightsInstrumentationKey" value="1234-5678-9xxx" />
In Application_Start we do the following to set the instrumentation key:
var instrumentationKey = ConfigurationManager.AppSettings["ApplicationInsightsInstrumentationKey"];
if (string.IsNullOrWhiteSpace(instrumentationKey))
{
throw new ConfigurationErrorsException("Missing app setting 'ApplicationInsightsInstrumentationKey' used for Application Insights");
}
TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey;
new TelemetryClient().TrackEvent("Application started");
However, this produces an exception saying "TelemetryChannel must be initialized before it can send telemetry".
Googling this exception message yields nothing, but I guess there's something additional required before events can be tracked?

Removing the <InstrumentationKey /> element from ApplicationInsights.config seems to do the trick.
I've done the exact same thing, setting the iKey in Application_Start() for a web application, and before I new() up a TelemetryClient in console applications. I do not have any element in my ApplicationInsights.config, not even a blank one. I keep a comment in that config file that says the key is being set programmatically.

Related

ASP.NET Core EventLog Not Registering

I've been trying to add an EventLog Provider for logging in my ASP.NET Application. I was able to add it to the 'Application' source, but there's a lot of information in that log and I'd like for it to be under it's own source. I've actually gotten 3 logs to be written to it's own source, but I have no idea how or why. This is what my code looks like right now:
CreateWebHostBuilder(args)
.ConfigureLogging( logging =>
{
logging.AddEventLog(
new Microsoft.Extensions.Logging.EventLog.EventLogSettings
{
SourceName = "MySweetApp",
MachineName = ".",
LogName = "MySweetApp",
Filter = (category, level) =>
{
if (category.EndsWith("Controller") || level >= LogLevel.Error)
{
return true;
}
return false;
},
});
})
.Build()
.Run();
I've already added a registry key there for this app (since the app doesn't have admin rights and can't add a source) along with the EventMessageFile of C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll. I've messed with different values of this including the non-64 framework folder and other v2 versions. There are no errors or warnings, and I can't find any logs that have anything related in them. I've also added a debug logger with .AddDebug() and it prints just fine the debug window.
I'm guessing it's something on the server side of things and not my code. Thanks in advance.
UPDATE: I can now re-create my app creating error logs in the eventlog. If I start my program by double-clicking the .exe, there is an authentication error that is thrown and gets sent to the log.
Found it. I still had a "Logging" section of my appsettings.json that was set default to warning. Deleted that section and everything started printing!

Azure doesn't pass my custom message in HttpException

I have a REST API in an Azure WebApp.
When a POST is sent to my endpoint I do some checks and if needed I throw an HttpException:
throw new HttpException(400, msgInfo);
Where msgInfo is my custom message. In my dev-machine using Visual Studio 2015 my response is:
{"Message":"An error has occurred.","ExceptionMessage":"[my custom message]","ExceptionType":"System.Web.HttpException","StackTrace":"..."}
Now I can show the user a useful message.
But on Azure the response is just:
{"Message":"An error has occurred."}
So no custom message.
Most likely this is a setting in Azure. I understand it should not show my full stack trace, but it should show ExceptionMessage.
In my Web.config I have:
<system.web>
<customErrors mode="RemoteOnly" />
</system.web>
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
How to fix this?
Asp.net web api has a separate configuration for how the error detail is shown in different environments.
In you HttpConfiguration, there is a property called IncludeErrorDetailPolicy. Here is its possible value.
public enum IncludeErrorDetailPolicy
{
// Summary:
// Use the default behavior for the host environment. For ASP.NET hosting, usethe value from the customErrors element in the Web.config file.
// For self-hosting, use the value System.Web.Http.IncludeErrorDetailPolicy.LocalOnly.
Default = 0,
// Summary:
// Only include error details when responding to a local request.
LocalOnly = 1,
//
// Summary:
// Always include error details.
Always = 2,
//
// Summary:
// Never include error details.
Never = 3,
}
You could configure as below:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCloudServiceGateway();
var config = new HttpConfiguration
{
IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always // Add this line to enable detail mode in release
};
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
For more details, you could refer to this thread.
Also, you could set <customErrors mode="Off"/>, which specifies that custom errors are disabled. The detailed ASP.NET errors are shown to the remote clients and to the local host.

Change a Line of Code based on Configuration selected

In my ASP.NET MVC 3 application, I have 2 configurations setup; Play and Live.
Right now, I have to change the following code before loading my application with a configuration based on what I currently have selected:
Mailer.SendMessageTo("playEmailAddress", "MailBody");
// Mailer.SendMessageTo("liveEmailAddress", "MailBody");
So if I have Play configuration selected I'll comment out the liveEmailAddress line and vice versa
What I'd like to do is perhaps make use of the web.config file to change this code for me without manually doing it every time I load up my application with a different configuration by putting the lines of code in the config file and then reading it from the config file from within my class
You should add the "app key" in your web configuration file. Give it anyname like "OptionalEmail" and set the value accordingly.
When you send the email check the value in the configuration file like
If(ConfigurationManager.AppSettings["OptionalEmail"]=="PlayEmail")
SendEmail using PlayEmail address else SendEmail using Work emai
Address.
Hope this help. "ConfigurationManager.AppSettings[use key or index]
Please keep in mind, Config Transformations "xdt" works only when you deploy your web application.
it's generally a good idea to have a configuration parameter named "environment" (or the like).
This link explains how to read from the web.config: http://msdn.microsoft.com/en-us/library/610xe886.aspx.
one way to implement this would be:
var env = "play";
if( ConfigurationManager.AppSettings["environment"]=="live" ) env="live";
var email = env + "EmailAddress";
Mailer.SendMessageTo(email, "MailBody");
as an additional note, if you have multiple developers that each want their own "play"-Address, then you can extend the setting to include the developers machine name:
<appSettings>
<add key="environment" value="play"/>
<add key="liveEmailAddress" value="a#b.com"/>
<add key="myCoolPC-playEmailAddress" value="c#d.com"/>
<add key="otherDevPC-playEmailAddress" value="bubba#test.com"/>
</appSettings>
but then you would have to change the implementation above to prefix the hostname before getting the setting, but only if currently in play-mode.

Log some information no matter what using log4net

Situation is that level of log4net is configured as 'Error' but there is some information i need to write under a 'no matter what' condition
for example
"loggin has started"
if only 'Error' or 'Fatal' is enabled i cant log this in Error or Fatal since its just information
so is there any way i can do that other than change the level of the logger to info, write the log and then change back the level because that will act just like a workaround not a solution
and without using Headers since they only come at the beginning
EDIT: In an Appender
StringMatchFilter stringFilter = new StringMatchFilter();
stringFilter.AcceptOnMatch = true;
stringFilter.StringToMatch = "successfully";
stringFilter.ActivateOptions();
appender.AddFilter(stringFilter);
DenyAllFilter deny = new DenyAllFilter();
deny.ActivateOptions();
appender.AddFilter(deny);
adding to an appender and setting level 'All' to the root and managing levels in appenders but still i am unable to write any message containing 'successfully'
but please note when i set appender level to info the filter begins to work
I assume this is all because you don't like the idea of using .FatalFormat when it is not really an error.
I'm not sure how you would do this programatically, but if you were using a config file you add a section like
<logger name="ALWAYS">
<level value="DEBUG" />
appender-ref ref="RollingFileAppender" />
</logger>
which means you can log your messages like
log4net.LogManager.GetLogger("Always").InfoFormat( ... );
or you could create a static
static readonly log4net.ILog alwaysLogger = log4net.LogManager.GetLogger("Always");
and log via.
alwaysLogger.InfoFormat(....);
My suggestion would be to create a filter that looks first at a string match and then at the level. That way you could have a key string that you pass in the message (say "AppInfo" or something that would be unique and not found in an error). Then, your filter would pick that up and log it even when you logged it at the INFO level but the filter would ignore all other messages that weren't ERROR or FATAL. I wrote an article on CodeProject that will show you how to do complex filtering like this:
http://www.codeproject.com/KB/dotnet/Log4net_Tutorial.aspx
The one key here is that you would probably need to not specify the filtering in the root for this particular appender, since root supersedes the appender if I remember correctly.

Is there any way to programmatically set the application name in Elmah?

I need to change the app name based on what configuration I'm using in Visual Studio. For example, if I'm in Debug configuration, I want the app name to show as 'App_Debug' in the Application field in the Elmah_Error table. Does anyone have any experience with this? Or is there another way to do it?
This can now be done purely in markup. Just add an applicationName attribute to the errorLog element in the <elmah> section of the web.config file. Example:
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="connectionString" applicationName="myApp" />
I've tested this and it works both when logging an exception and when viewing the log via Elmah.axd.
In the case of the OP, one would imagine it can be set programatically too but I didn't test that. For me and I imagine for most scenarios the markup approach is sufficient.
By default, Elmah uses the AppPool's application GUID as the default application name. It uses this as the key to identify the errors in the Elmah_Error table when you look at the web interface that's created through it's HTTP Module.
I was tasked to explore this option for my company earlier this year. I couldn't find a way to manipulate this by default since Elmah pulls the application name from HttpRuntime.AppDomainAppId in the ErrorLog.cs file. You could manipulate it by whatever key you want; however, that is the AppPool's GUID.
With that said, I was able to manipulate the ErrorLog.cs file to turn Elmah into a callable framework instead of a handler based one and allow for me set the ApplicationName. What I ended up doing was modifying ErrorLog.cs to include a property that allowed me to set the name as below:
public virtual string ApplicationName
{
get
{
if (_applicationName == null) { _applicationName = HttpRuntime.AppDomainAppId; }
return _applicationName;
}
set { _applicationName = value; }
}
What you will probably need to do is adjust this differently and set the ApplicationName not to HttpRuntime.AppDomainAppId but, instead, a value pulled from the web.config. All in all, it's possible. The way I did it enhanced the ErrorLog.Log(ex) method so I could use Elmah has a callable framework beyond web applications. Looking back I wish I did the app/web.config approach instead.
One thing to keep in mind when changing the application name in Elmah. The http handler that generates the /elmah/default.aspx interface will no longer work. I'm still trying to find time to circle back around to such; however, you may need to look into creating a custom interface when implementing.

Categories