I have a website on appharbor.
I know there is logentries for logs on demand.
But, how can I see all unhandled server-side exceptions?
I have found this snippet (to put int Global.ascx), but couldn't find what are all the required dlls to reference.
protected void Application_Error(object sender, EventArgs e)
{
try
{
var exception = Server.GetLastError();
var logEntry = new LogEntry
{
Date = DateTime.Now,
Message = exception.Message,
StackTrace = exception.StackTrace,
};
var datacontext = new LogDBDataContext();
datacontext.LogEntries.InsertOnSubmit(logEntry);
datacontext.SubmitChanges();
}
catch (Exception)
{
// failed to record exception
}
}
AppHarbor already logs application errors, you can inspect them by clicking "Errors" in the menu to the left of the application dashboard.
Another great option is to add Elmah to your AppHarbor application, but remember to lock down Elmah view.
Should you still want to use the snippet above, then take a look at the full sample to see what other dependencies are required.
Related
I create a setup file of a winform app using VS 2017 installer. When I test this setup file on my PC, the login runs fine. So I run this setup file on other PCs.
However, when I login the app in these PCs, the app say "Object reference not set to an instance of an object", though I am sure that the username and password were correct in the db.
I have seen What is a NullReferenceException, and how do I fix it?, but I do not think it is the null exception, because the installed app did not throw above error in my PC. This error only happens when I install the app in other PCs.
I also try replacing the .exe and .config files in folder of the installed app in other PCs with the same files of the app in my PC (which work well), and the app runs ok. But then I restart those PCs, and try to login the app, the same error happens.
This is the code for login. I believe that I have checked for the null exception properly. Am I right?
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
var info = UsersBiz.Login(txtUserName.Text.Trim(), txtPassWord.Text);
if (info != null && info.user.Id > 0)
{
Constants.USERINFO = info;
this.Hide();
var frm = new frmMain();
frm.Show();
if (ckbRemember.Checked)
{
ManagementInventory.Properties.Settings.Default.User = txtUserName.Text;
ManagementInventory.Properties.Settings.Default.Pass = txtPassWord.Text;
ManagementInventory.Properties.Settings.Default.Save();
}
}
else
{
MessageBox.Show("UserName or Password not correct!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The most easy way would be to use visual studio debugger on the computer where the program runs. If there is no visual studio on that computer, consider using remote debugging. See how to start debugging on a remote computer
If for security reasons remote debugging is out of the question, consider to log the exception, especially the stack trace. If you know where it occurs, simply surround it with a try-catch
try
{
// Here are the statements that cause your ArgumentNullException
}
catch (ArgumentNullException exc)
{
// log the exception
}
If your program has no logging facility, consider adding something like NLOG. Another possibility is to append it to a text file.
void WriteExceptionToTextFile(Exception exc, string fileName)
{
using (var writer = File.AppendText(fileName))
{
writer.WriteLine("Exception {0}", exc.GetType());
write.WriteLine("Stack trace" + exc.StackTrace);
... // etc
}
}
If you don't know where the exception occurs, you can't try-catch it. In that case consider to catch the unhandled exception and log it:
See: catching unhandled exception
In your forms program is a file program.cs which contains the main:
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += OnUnhandledException;
...
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception undhandledException = (Exception) args.ExceptionObject;
// TODO log the unhandled exception
}
I found several topics on this already, but somehow they all managed to avoid the real problem solution/assumed the obvious.
(e.g. here, here, here, here, here)
I am checking for and creating new event log + source during installation, and specifying them to be used during operation, but still somehow "EventSourceName" events end up in Application Log.
Why is that?
Here are snippets out of my code:
Installer:
namespace Service_Name
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
if (!System.Diagnostics.EventLog.SourceExists("EventSourceName"))
{
System.Diagnostics.EventLog.CreateEventSource(
"EventSourceName", "EventLogName");
}
InitializeComponent();
}
private void serviceProcessInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
}
}
}
Service:
public Service_Name()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ServiceEventLog = new EventLog();
ServiceEventLog.Source = "EventSourceName"; // This is different from Service Name
ServiceEventLog.Log = "EventLogName"; // This is different from Service Name
..
ServiceEventLog.WriteEntry("Service Init");
Worker = new Thread(CodeWorker);
Worker.Start();
}
private void CodeWorker()
{
//.. operational code
while (true)
{
try
{
//.. operational code
ServiceEventLog.WriteEntry("<operational event data here>", (EventLogEntryType)4, 0);
}
catch (Exception Error)
{
ServiceEventLog.WriteEntry(string.Format("<error event data here>", (EventLogEntryType)1, 0);
throw;
}
//.. operational code
}
}
As it turns out, the code works perfectly as is, however there is important thing to remember when working with event log;
EventLog.CreateEventSource Method has an important footnote:
If a source has already been mapped to a log and you remap it to a new
log, you must restart the computer for the changes to take effect.
I had mapped the source prior, to another event log which was named the same as Service itself. Using same name as the service itself caused multiple other issues and I ended up fixing that by using another log name, but did not restart test system prior to doing tests on new code version.
But as Caius Jard pointed out below, parts of the code are redundant:
ServiceEventLog.Log = "EventLogName" does not need to be specified as Source is already registered to Log.
The documentation states "If you change the Log property after the Source property has been set, writing a log entry throws an exception.".
The sample code on MSDN just sets the Source property and then calls WriteEvent, it does not then set the Log beforehand or after setting Source
I recommend you remove the call to setting the Log property; I suspect your call to WriteEvent is crashing, and being in a try catch the call in the catch is also crashing. Perhaps it's not an ideal code structure to "try writing to this log and if it fails, try writing to this log" if it's the "writing to log" that is failing
I'm trying to create an availability page which checks all the services that a site uses, wrapping each check in a try/catch and then displaying any failures to the users. One of those services is ELMAH, so I am calling that to double check that we can log errors there successfully.
Controller:
var a = new AvailabilityModel();
try {
a.ElmahConnectionString = ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString;
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Elmah availability test"));
a.ElmahSuccess = true;
} catch (Exception ex) {
a.ElmahSuccess = false;
a.ElmahException = ex;
Response.StatusCode = 503;
}
return View(a);
When ELMAH succeeds, all is well. When it throws any kind of error (DB permissions, etc.), I get an error which is not captured by the try/catch OR by any of the normal error-capturing pieces: ASP.NET MVC HandleError, customErrors redirects, or even httpErrors in system.webServer. The display is not the normal IIS generic message, instead I see a single line saying "The service is unavailable."
Response:
LTSB-W34511 C:\s\d\build % curl -i http://server/test/availability
HTTP/1.1 503 Service Unavailable
Cache-Control: public, max-age=14400, s-maxage=0
Content-Type: text/html
Server: Microsoft-IIS/7.5 X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 06 Aug 2014 15:46:55 GMT
Content-Length: 27
The service is unavailable.
And that's it. At least I know my availability is not working, but I want to at least display to the user that it's ELMAH causing the problem, and show the connection string it's trying to use. So, I need to capture this exception somehow.
I've tried tweaking my web.config a number of different ways, but I suspect there's something about the way ELMAH inserts itself into the module pipeline which stops me from handling the issue.
Edit:
To clarify, this is a simplified example. I am not planning to expose this information to end users. This availability page will only be available to internal users who are troubleshooting future issues.
ELMAH is only one of the services/databases used by the application in question, and I want to give administrators a quick dashboard-like view of what is up and down. I can't do that if ELMAH errors lead to this insta-503.
Ok, basically this is not possible without any code. The Raise method in Elmah will not let you see any error except if you trace it:
// ErrorLogModule.LogException
try
{
Error error = new Error(e, context);
ErrorLog errorLog = this.GetErrorLog(context);
error.ApplicationName = errorLog.ApplicationName;
string id = errorLog.Log(error);
errorLogEntry = new ErrorLogEntry(errorLog, id, error);
}
catch (Exception value)
{
Trace.WriteLine(value);
}
However when the event is successfully logged the ErrorLogModule will call the logged event in order to let potential listeners know that the logging was a success. So let's quickly write a custom class that will override some methods from the ErrorLogModule and will allow us to notice that the event was not logged:
public class CustomErrorLogModule: Elmah.ErrorLogModule
{
public Boolean SomethingWasLogged { get; set; }
protected override void OnLogged(Elmah.ErrorLoggedEventArgs args)
{
SomethingWasLogged = true;
base.OnLogged(args);
}
protected override void LogException(Exception e, HttpContext context)
{
SomethingWasLogged = false;
base.LogException(e, context);
if (!SomethingWasLogged)
{
throw new InvalidOperationException("An error was not logged");
}
}
}
Swap the ErrorLogModule with the CustomErrorLogModule in your configuration file and Elmah will complain when something wrong is happening; calling Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test")); in a test page lets the InvalidOperationException("An error was not logged") be thrown out of the call.
If you want to get back the exact exception that occured when trying to log the exception, you can use the fact that the ErrorLogModule traces the exception when it occurs. Create a listener class:
public class ExceptionInterceptor : DefaultTraceListener
{
public Exception TracedException { get; set; }
public override void WriteLine(object o)
{
var exception = o as Exception;
if (exception != null)
{
TracedException = exception;
}
}
}
Then your LogException method becomes
protected override void LogException(Exception e, HttpContext context)
{
var exceptionListener = new ExceptionInterceptor();
Trace.Listeners.Add(exceptionListener);
try
{
SomethingWasLogged = false;
base.LogException(e, context);
if (!SomethingWasLogged)
{
throw exceptionListener.TracedException;
}
}
finally
{
Trace.Listeners.Remove(exceptionListener);
}
}
EDIT: or even if you want to be as terse as possible
public class ExceptionInterceptor : DefaultTraceListener
{
public override void WriteLine(object o)
{
var exception = o as Exception;
if (exception != null)
{
throw exception;
}
}
}
// snip... LogException in your CustomErrorLogModule
protected override void LogException(Exception e, HttpContext context)
{
var exceptionListener = new ExceptionInterceptor();
Trace.Listeners.Add(exceptionListener);
try
{
base.LogException(e, context);
}
finally
{
Trace.Listeners.Remove(exceptionListener);
}
}
One final word: There is a smell in this way of checking for service availability, and you are going to pepper your error database with test exceptions which may not be the desired behavior. I understand that you aim to check the whole logging chain but perhaps there could be some other way to do it; I don't really know your context so I won't comment any further but don't hesitate to think on it.
Anyway, these changes should let you receive the exception you will need.
important edit: very important point: you may want to add a trigger to your CustomErrorLogModule so it doesn't throw when you are not testing. The resilience you are observing in Elmah is generally a good thing because you don't want a diagnostic platform to cause problems that may necessitate other diagnostics. That's why Elmah or logging frameworks don't throw, and that's why you should make the exception rethrowing mechanism triggerable so your program doesn't have to watch its step when raising exceptions in Elmah.
No, no no! Never display the connection string to the user and never tell them what the problem is. Doing so is a serious security vulnerability. Simply put, don't do it. Fix your underlying problems with Elmah.
Problems in your error handling pipeline are very bad, because it'll cause it to try to handle the new error that's generated, which basically causes a loop. The ASP.NET engine recognizes that something serious has gone wrong, so it gives a generic "the service is unavailable" message. Check the event logs on your server to find out the underlying Elmah error and correct it.
My application calls a library (which I do not have control) that creates a new EventLog source and uses EventLog.SourceExists. It throws System.Security.SecurityException: The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.
The app needs read access to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Security. How do I give Network Service permissions to registry (programmatically)?
Thanks for any pointers.
You are getting this error message because your "new Source" is not registered, and for that you need administration privileges. Try run your APP as "Administrator" in Console.
I once hacked the "registry" as well, by adding in the "Source" myself, but that's probably ill-advised.
I hit this same problem today and none of the answers for WinForms or ASPX seemed practicable for my situation (a non-installing scheduled task exe). So I did this: -
protected void prog_Load(object sender, EventArgs e)
{
boolean setupComplete = false;
try // setting an Event log entry, just to see if we can
{
logEvent = "prog started";
EventLog.WriteEntry(logSource, logEvent, EventLogEntryType.Information, 0);
setupComplete = true;
}
catch (Exception eLog1) // we can't, so try to fix
{
try
{
EventLog.CreateEventSource(logSource, logLog);
logEvent = "prog registered for Event Logging";
EventLog.WriteEntry(logSource, logEvent, EventLogEntryType.Information, 0);
}
catch (Exception eLog2) // aha! we probably lack admin rights to set the registry key
{
MessageBox.Show("prog needs admin rights the first time it runs", "prog Setup", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// run
if (setupComplete == true)
{
DoTheWork();
}
// exit
this.Close();
}
I'm a bit confused at how to add a message to an error logged programatically with ELMAH.
eg:
public ActionResult DoSomething(int id)
{
try { ... }
catch (Exception e)
{
// I want to include the 'id' param value here, and maybe some
// other stuff, but how?
ErrorSignal.FromCurrentContext().Raise(e);
}
}
It seems all Elmah can do is log the raw exception, how can I also log my own debug info?
You can throw a new Exception setting the original as the inner exception and ELMAH will log the messages for both:
catch(Exception e)
{
Exception ex = new Exception("ID = 1", e);
ErrorSignal.FromCurrentContext().Raise(ex);
}
will show
System.Exception: ID = 1 ---> System.NullReferenceException: Object reference not set to an instance of an object.
I found that I can also do something like:
Elmah.ErrorSignal.FromCurrentContext().Raise(new NotImplementedException("class FbCallback.Page_Load() Request.Url= " + Request.Url));
To log my own messages. Then in when I browse to
http://localhost:5050/elmah.axd
I see my messages as type NotImplementedException.
Not very pretty but works.