Exception.Data info is missing in EntLib log - c#

How do I get the Exception Handling Application Block (EHAB) to write the values from the Exception.Data property in the log?
try
{
// ...
}
catch (Exception ex)
{
ex.Data.Add("Hello", "World");
throw ex;
}
The exception is logged correctly, but I can’t find the added data anywhere in the log entry created by EHAB.
As far as I understand, it’s a recommended practice to add additional relevant information to the exception itself like in the above example. That’s why I’m a little surprised that EHAB doesn’t include this by default.
Can I fix this by modifying the template with the EntLib Text Formatter Template Editor (screen shot below)? I can't find any info on the various "tokens" provided, but I assume the answer is hidden somewhere with them.
Text Formatter Template Editor http://img195.imageshack.us/img195/6614/capturegmg.png
Or do I really need to implement my own custom Text Formatter to accomplish this?
EDIT/UPDATE:
I do this in my Global.asax.cs in order to avoid having to add the HandleException method call everywhere in my code:
using EntLib = Microsoft.Practices.EnterpriseLibrary;
using System;
namespace MyApp
{
public class Global : System.Web.HttpApplication
{
protected void Application_Error(object sender, EventArgs e)
{
// I have an "All Exceptions" policy in place...
EntLib.ExceptionHandling.ExceptionPolicy.HandleException(Server.GetLastError(), "All Exceptions");
// I believe it's the GetLastError that's somehow returning a "lessor" exception
}
}
}
It turns out this is not the same as this (which works fine, and essentially solves my problem):
try
{
// ...
}
catch (Exception ex)
{
ex.Data.Add("Hello", "World");
bool rethrow = ExceptionPolicy.HandleException(ex, "Log Only Policy");
throw ex;
}
Going through all the code and adding try-catch's with a HandleException call just seems ... well, stupid.
I guess my problem really is how to use EHAB correctly, not configuration.
Any suggestion on how I can properly log all exceptions on a "global level" in an ASP.NET web application??

You shouldn't have to create your own formatter.
Each item in the Data IDictionary on the Exception object is added to the ExtendedProperties Dictionary of the LogEntry object and is logged (if specified by the formatter).
The Extended Properties:{dictionary({key} - {value})} config snippet should log all key/value pairs in the extended properties dictionary. If you want to log just one item from the collection you can use "keyvalue". In your example it would be something along the lines of:
Hello Key: {keyvalue(Hello)}
I modified the ExceptionHandlingWithLoggingQuickStart to add Data.Add("Hello", "World") and I see "Extended Properties: Hello - World" at the end of the Event Log entry. So it is working.
If you aren't seeing that behavior, you need to ensure:
That your exception with the Data items added is passed in to ExceptionPolicy.HandleException
That the policy specified in the HandleException method is configured for logging with a LoggingExceptionHandler in the configuration
That the formatter that is specified in the LoggingConfiguration is configured to support ExtendedProperties
If you can't see what the problem is try comparing what you have with what is in the QuickStart. If it's still not working, post your code and your config.
UPDATE:
If you are going to handle Application_Error in the global.asax then you will be receiving an HttpUnhandledException since the page did not handle the error. You can retrieve the Exception you are interested in by using the InnerException Property; the InnerException will contain the original Exception (unless it is in that exception's InnerException :) ). Alternately, you can use Server.GetLastError().GetBaseException() to retrieve the exception which is the root cause.

Related

How to bypass FileNotFoundException

I have an text file which has some settings parameters for my project. My desktop layer reads this file. Therewithal , web layer's project read from from Server's MapPath.
FileStream has no operator to bypass an exception.I have tried to Exists control. But , i just need to bypass FileNotFoundException.
Place the code in a try catch.
try
{
//read
}
catch(FileNotFoundException ex)
{
//do logging for this silent catch
Console.WriteLine(ex);
}
How about this,
if (File.Exists(path)
{
// read file,
}
Another way,
if (File.Exists(path)
{
try
{
// read file,
}
catch (Some other exception related to file, read access violation, etc.)
{
handle exception,
}
}
How about checking the file exists or not?
if so, you can prevent throwing FileNotFoundException.
[Can not provide complete solution/feedback as we aren't sure about your actual implementation]
If(!File.Exists(<path_to_file>)
return;
// continue doing the rest only if file exists
Hope this helps. let us know if require more clarifications. It Would be nice if you could post your method implementation or at least a pseudo code for us to understand the actual problem you trying to solve.
Cheers,

Message read by OnEntryWritten are coming with parameters not set

I'm using the OnEntryWritten event in order to get events from the event log when they are fired.
The problem I started to see today is that some messages come with parameters unset.
For example:
The Windows Filtering Platform has permitted a bind to a local port. Application Information: Process ID:9852 Application Name:\device\harddiskvolume7\program files (x86)\google\chrome\application\chrome.exe Network Information: Source Address::: Source Port:51714 Protocol:17 Filter Information: Filter Run-Time ID:0 Layer Name:%%14608 Layer Run-Time ID:38
You can see the %%14608 parameter. This comes with a value if I see the same log in the Event Viewer.
I'm running a windows service as LocalSystem, so I don't know if this is a permission issue or this technology is not useful at all.
I have tried the rest offered on C# and they also don't meet my requirements.
UPDATE: this is the code I'm using to read the events.
1) First I subscribe to the corresponding Event log:
private void Subscribe()
{
_eventLog.EnableRaisingEvents = true;
var callbackFunction = new EntryWrittenEventHandler(OnEntryWritten);
_eventLog.EntryWritten += callbackFunction;
// Save a reference for callbackFunction
_eventHandler = callbackFunction;
}
2) Then on the callback method, I read data from the message:
public void OnEntryWritten(Object source, EntryWrittenEventArgs entryArgs)
{
// When overwrite policy is enabled, this will trigger for all elements when it starts writing new ones
try
{
var entry = entryArgs.Entry;
var timeWritten = entry.TimeWritten;
// This comes with %% values depending on the log
string message = entry.Message;
}
catch(Exception ex)
{
...
}
}
3) The event log variable is simply initialized as:
var eventLog = EventLog.GetEventLogs().FirstOrDefault(el => el.Log.Equals(logName, StringComparison.OrdinalIgnoreCase));
I need some help on this, honestly I don't know what else to try.
UPDATE
I'm adding some images here so everybody can understand the situation a little bit better. To be honest, it looks like there's no solution but to implement a dictionary and replace manually the required values, which appear to be always constants.
This is what I see on the Event Viewer for a given Event ID:
This is what I see on my program when I read that entry:
You can clearly see that the following values:
"Machine key." (Key type)
"Read persisted key from file." (Operation)
Are coming unmapped in the ReplacementStrings and the Message properties as: %%2499 and %%2458
This is the message value I get on the program:
"Key file operation.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tMyAccount$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3e7\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t6644\r\n\tProcess Creation Time:\t2019-04-03T12:17:24.587994400Z\r\n\r\nCryptographic Parameters:\r\n\tProvider Name:\tMicrosoft Software Key Storage Provider\r\n\tAlgorithm Name:\tUNKNOWN\r\n\tKey Name:\t816339d2-c476-4f1e-bc40-954f0aa0f851\r\n\tKey Type:\t%%2499\r\n\r\nKey File Operation Information:\r\n\tFile Path:\tC:\ProgramData\Microsoft\Crypto\Keys\6d55a45fd69327293e9ed3e7930f4565_5663a8bb-2d1d-4c0d-90c1-624beddabe9c\r\n\tOperation:\t%%2458\r\n\tReturn Code:\t0x0"
What can be done here? There also nothing in entry.Data that might help me out to obtain both values.
No, I believe you're mistaken, sorry that this answer is too late. I found a similar event that was raised by chrome and evaluated if there's anything missed by the event handler. There wasn't anything missed. The message I got in my console output exactly matched what I saw in my Event Viewer.
A better solution would be to
Use entry.Data to get the complete data instead of entry.Message
entry.Data will return a byte[] which you can convert to a string. Here's the link to all properties that an entry will have.

Schematron.net structured error reporting

I am using the Schematron.net nuget package and I want to know if it's possible to get the output of a call to Validate to give the results in a structured format that I can then process. My existing solution relies on a try catch block and the assertion failures are all returned as the message within the exception as the error message. Is there a way to get this information as XML? I have seen this post which asks a similar question, but the answers don't refer to the Schematron.net implementation.
My code looks like this:
try
{
var bookValidator = new Validator();
bookValidator.AddSchema("book.xsd");
bookValidator.Validate("book.xml");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
It's pretty simple actually. I just realised that passing a suitable enumeration of OutputFormatting to the Validator constructor allows me to control the format of the message in the exception, like so:
try
{
//OutputFormatting is a public enum from the Schematron library. Valid values include boolean, default, Log, simple and XML.
OutputFormatting format = OutputFormatting.XML;
var bookValidator = new Validator(format);
bookValidator.AddSchema("book.xsd");
bookValidator.Validate("book.xml");
}
catch (Exception ex)
{
//ex.Message will now be in XML format and can be processed however I want!
Console.WriteLine(ex.Message);
}
And there's your structured results. I hope that helps someone as it wasn't obvious to me.

How to keep XmlWriterTraceListener from xml-encoding characters in the message

I am trying to use System.Diagnostics.XmlWriterTraceListener to log to a local file. I start by creating a source and adding a new XmlWriterTraceListener to it, like so:
public class Logger
{
const string LOG_ERR_FMT = "<message><![CDATA[{0}]]></message>{2}";
TraceSource tSource = new TraceSource(
"MyApp",
SourceLevels.Verbose | SourceLevels.ActivityTracing
);
public Logger() {
tSource.Listeners.Add(
new XmlWriterTraceListener("C:\\app_path\\app_tracelog.svclog", "LocalListener")
);
}
public static Logger defLogger = new Logger();
public static Logger Default {
get {return defLogger; }
set { if (value != null) defLogger = value; }
}
public void LogError(string msg, string extraXmlData) {
tSource.TraceEvent(TraceEventType.Error, 0, LOG_ERR_FMT, logMsg, extraXmlData);
}
}
I've simplified the log format in the sample above. The actual LogError method takes an Exception object and inserts some xml-serialized data about it into the message, but that's not needed to show what my problem is here.
Anyways, any other part of my app can now log an error to the "app_tracelog.svclog" file with a simple line like, oh say...
Logger.Default.LogError(
"Error parsing response from web service \"someservice.com\".",
"<RequestBody><![CDATA[" + responseBody + "]]></RequestBody>"
);
All is well until I open up app_tracelog.svclog. First of all, when I try to open it with Microsoft Service Trace Viewer, that program behaves like it's empty, and gives me a message of "There is no trace loaded from the file."
Second, I open the file with good old Notepad++ and find that my app DID INDEED log to it. I select all and tell XmlTools to pretty it up, and the tool tells me it can't do it because there's errors in the XML.
So, I start formatting it manually. All goes well at first, until I get to the actual application message that I logged. Here, I find that this STUPID ##$ class has screwed up all my nested XML by replacing brackets and such with encoded XML/HTML entities!
All my '<'s have become "<", All my '>'s have become ">", etc... So the log message that SHOULD have looked like:
<message><![CDATA[Error parsing response from web service "someservice.com".]]></message><RequestBody...
Now looks like:
<message><![CDATA[Error parsing response from web service "someservice.com".]]></message><RequestBody...
So the big question is: How can I FORCE XmlWriterTraceListener to stop trashing my message when I log? I know what I'm doing when I put in special XML characters, and it thinks it knows better! --OR- Is there another listener class that will log to a local XML file the way I want?

Intercept SQL statements containing parameter values generated by NHibernate

I use a simple interceptor to intercept the sql string that nhibernate generates for loging purposes and it works fine.
public class SessionManagerSQLInterceptor : EmptyInterceptor, IInterceptor
{
NHibernate.SqlCommand.SqlString IInterceptor.OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
{
NHSessionManager.Instance.NHibernateSQL = sql.ToString();
return sql;
}
}
This however captures the sql statement without the parameter values.. They are replaced by '?'
Eg: .... WHERE USER0_.USERNAME = ?
The only alternative approach i found so far is using log4nets nhibernate.sql appender which logs sql statement including parameter values but that is not serving me well..
I need to use an interceptor so that for eg. when i catch an exception i want to log the specific sql statement that caused the persistence problem including the values it contained and log it mail it etc. This speeds up debuging great deal compared to going into log files looking for the query that caused the problem..
How can i get full sql statements including parameter values that nhibernate generate on runtime?
Here is (roughly sketched) what I did:
Create a custom implementation of the IDbCommand interface, which internally delegates all to the real work to SqlCommand (assume it is called LoggingDbCommand for the purpose of discussion).
Create a derived class of the NHibernate class SqlClientDriver. It should look something like this:
public class LoggingSqlClientDriver : SqlClientDriver
{
public override IDbCommand CreateCommand()
{
return new LoggingDbCommand(base.CreateCommand());
}
}
Register your Client Driver in the NHibernate Configuration (see NHibernate docs for details).
Mind you, I did all this for NHibernate 1.1.2 so there might be some changes required for newer versions. But I guess the idea itself will still be working.
OK, the real meat will be in your implementation of LoggingDbCommand. I will only draft you some example method implementations, but I guess you'll get the picture and can do likewise for the other Execute*() methods.:
public int ExecuteNonQuery()
{
try
{
// m_command holds the inner, true, SqlCommand object.
return m_command.ExecuteNonQuery();
}
catch
{
LogCommand();
throw; // pass exception on!
}
}
The guts are, of course, in the LogCommand() method, in which you have "full access" to all the details of the executed command:
The command text (with the parameter placeholders in it like specified) through m_command.CommandText
The parameters and their values through to the m_command.Parameters collection
What is left to do (I've done it but can't post due to contracts - lame but true, sorry) is to assemble that information into a proper SQL-string (hint: don't bother replacing the parameters in the command text, just list them underneath like NHibernate's own logger does).
Sidebar: You might want to refrain from even attempting to log if the the exception is something considered fatal (AccessViolationException, OOM, etc.) to make sure you don't make things worse by trying to log in the face of something already pretty catastrophic.
Example:
try
{
// ... same as above ...
}
catch (Exception ex)
{
if (!(ex is OutOfMemoryException || ex is AccessViolationException || /* others */)
LogCommand();
throw; // rethrow! original exception.
}
It is simpler (and works for all NH versions) to do this :
public class LoggingSqlClientDriver : SqlClientDriver
{
public override IDbCommand GenerateCommand(CommandType type, NHibernate.SqlCommand.SqlString sqlString, NHibernate.SqlTypes.SqlType[] parameterTypes)
{
SqlCommand command = (SqlCommand)base.GenerateCommand(type, sqlString, parameterTypes);
LogCommand(command);
return command;
}}
Just an idea: can you implement a new log4net-appender, which takes all sqlstatements(debug with parameter) and holds the last one. When an error occured you can ask him for the last sqlstatement and email it.
Implement custom ILoggerFactory and filter in LoggerFor for keyName equals NHibernate.SQL and set via LoggerProvider.SetLoggersFactory. Works for SQLite driver, should work for other.
LoggerProvider by default creates log4net via reflection if log4net assembly presented. So best implementation would be if custom ILoggerFactory will delegate log into default, until NHibernate.SQL log requested.

Categories

Resources